많은 글을 참고했다. 어쩌면 이보다 더 많은 글을 봤을 수도.
https://blackperl-security.gitlab.io/blog/2018/02/15/2018-02-15-codegate2018-baskinrobbins31/
https://j0n9hyun.xyz/writeups/pwn/baskinrobbins31/
https://rookie0705.tistory.com/5
https://advancedpersistentjest.com/2018/02/04/writeup-baskinrobins31-codegate/
0. 시작 전
IDA를 설치하는 것부터가 난관이었다. 세 번은 깔았다 지웠다 한 것 같다.
IDA를 처음 설치하고 처음 써보는 거라서 너무 어려웠다.
구글링 하면서 최대한 따라해봤다.
처음에 파일이 뜨지 않아서 너무 당황스러웠다. 거의 1시간 동안 왜 파일이 안 뜨나 답답했는데
All Files (*)로 안 해서 그런거였다.. 몽총이
파일을 선택하고 OK를 눌렀다.
정상적으로 불러왔다.
1. Psedu Code 읽기 ( 코드 분석 )
Functions window에서 함수를 더블클릭 한 후에 F5를 누르면 Psedu Code를 읽을 수 있다.
1) main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
unsigned int v5; // [rsp+8h] [rbp-8h]
_BOOL4 v6; // [rsp+Ch] [rbp-4h]
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v3 = time(0LL);
srand(v3);
v5 = 31;
v6 = 0;
puts("### This game is similar to the BaskinRobins31 game. ###");
puts("### The one that take the last match win ###");
printf("There are %u number(s)\n", 31LL);
while ( (int)v5 > 0 )
{
if ( v6 )
{
my_turn(&v5);
v6 = 0;
}
else
{
v6 = (unsigned __int64)your_turn(&v5) != 0;
}
printf("remaining number(s) : %i \n", v5);
}
if ( v6 )
{
puts("Wow! You win!");
puts("Hint is : ROP");
}
else
{
puts("You lose!");
}
return 0;
}
|
cs |
unsigned int
unsigned int는 음수를 가지지 않으며 0과 양의 정수만 갖는 자료형이다.
숫자에서 sign은 부호를 의미하는데, unsigned이니까 부호가 없음을 의미한다.
0LL
0LL은 C언어와 C++에서 쓰이는 상수이다.
0 뒤에 붙는 LL은 longlong 타입의 상수임을 의미한다.
srand( )
rand와 srand 모두 난수를 생성하는 함수이다.
rand( )는 프로그램이 생성될 때 값이 이미 값이 정해지기 때문에 프로그램을 계속 실행해도 똑같은 값이 나오게 된다.
srand( )는 rand의 값을 초기화하는 역할이다.
프로그램이 실행 중일 때 항상 바뀌는 seed값을 이용해서 프로그램이 실행될 때마다 다른 난수가 나오도록 할 수 있다.
조건문 안에 있는 my_turn, your_turn 함수를 들여다보자.
2) your_turn (사용자 차례)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
__int64 __fastcall your_turn(_DWORD *a1)
{
__int64 result; // rax
__int64 v2; // [rsp-B0h] [rbp-B0h]
size_t v3; // [rsp-10h] [rbp-10h]
int v4; // [rsp-4h] [rbp-4h]
v4 = 0;
memset(&v2, 0, 0x96uLL);
puts("How many numbers do you want to take ? (1-3)");
v3 = read(0, &v2, 0x190uLL);
write(1, &v2, v3);
putchar(10);
v4 = strtoul((const char *)&v2, 0LL, 10);
if ( (unsigned int)check_decision((unsigned int)(char)v4) )
{
*a1 -= v4;
result = 1LL;
}
else
{
puts("Don't break the rules...:( ");
result = 0LL;
}
return result;
}
|
cs |
your_turn은 사용자 차례일 때 실행되는 함수이다. 사용자에게 하나의 숫자를 입력받은 후
return 하는 것이 이 함수의 역할이다.
:3
v2의 버퍼의 크기가 0xb0이다.
:12
read()는 데이터를 문자열로 입력받는 함수이다.
v2에 0x190만큼 값을 입력받는다.
:15
문자열로 받은 v2를 숫자로 바꿔준다. (strtoul)
:16 if문
1부터 3사이의 값을 입력하면 올바른 값!
:21 else문
올바르지 않은 값을 입력하면 "Don't break the rules"를 출력한다.
3번줄과 12번줄을 봤을 때,
버퍼의 크기가 0xb0인데 입력은 0x190만큼 받기 때문에 BOF가 발생하는 것을 알 수 있다.
2. Exploit Code 작성
받은 binary 파일을 우분투로 어떻게 가져와야 되는지 엄청 해맸다.
Drag and Drop으로 그냥 슉 하면 된다는 친구가 있었다.구글링을 해보니 vmware에서 drag and drop 하려면
vmware tools를 깔면 된다고 되어있었다.
음.. 깔았는데도 안 됐다.
그냥 메일 내게쓰기해서 다운로드 받았다...
어떤 기법이 걸려있는지 보자.
Partial RELRO와 NX bit가 걸려있다.
Canary와 PIE가 걸려있지 않다.
NX bit가 걸려있으니깐 쉘코드는 사용할 수 없다.
지난번에 했던 Return To Library를 이용해서 /bin/sh 문자열의 주소를 구하고
read함수에서 /bin/sh를 실행한다.
pwntools에서 libc symbols를 이용해서 바로 주소값을 구했다.
:10
rdi는 0x0000000000400bc3이다.
:12~14
puts의 주소를 알아내기 위한 코드이다.
payload에 "A"를 0xb8만큼 곱해준 값을 넣어주고 rdi값도 더해준다.
:15
ret을 건드리면 코드가 망가지기 때문에 main으로 다시 되돌려야한다.
:21 이 부분은 구글링을 했다.
r.recv(6) : 데이터를 6만큼 받겠다.
( ).ljust(8,"\x00") : 왼쪽부터 8칸을 \x00으로 확보한다.
:22
puts를 leak한다.
:23
system의 주소를 구한다.
3. Exploit
Error
Exploit 코드를 쓰고 돌렸는데 저런 에러가 뜬다.
AttributeError : 'int' object has no attribute 'symbols'
속성 이름을 잘못 입력하거나 없는 속성을 불러오려고 할 때 뜨는 에러라고 한다.
음.. 익스코드를 다시 보니까 5번줄과 21번줄의 변수이름이 겹쳐서 그런 것이었다.
22번줄의 libc를 lb로 바꾸어써야겠다.
근데도 에러가 난다.
혹시나 rdi를 잘못구했나 다시 한 번 봤는데 문제가 없는 것 같다.
재호의 도움을 받아서 21번줄을 바꿔봤다.
leak = u64(r.recv(6) + "\00\00")
리틀엔디안 방식으로 언패킹을 하기 위해서는 __ __ __ __ __ __ __ __ 처럼 8자리를 채워줘야하는데
라이브러리가 6자리니까 아무것도 없다는 뜻으로 뒤에 00 00을 채워주는 것이다.
바꿨는데도 같은 오류가 계속 난다.
아..
잘못 입력해야 Don't break the rules가 뜨기 때문에 payload를 보낸 다음에 "("를 받는 코드로 썼어야됐는데
17번줄과 18번줄 순서를 거꾸로 썼다.
코드를 수정했다.
으 이제 된다.
도와준 재호한테 정말 고맙다 ㅠㅠ
'Sunrin > Layer7' 카테고리의 다른 글
Stack pivoting (0) | 2020.09.08 |
---|---|
운영체제의 메모리 할당 알고리즘 (0) | 2020.09.02 |
Web hacking project idea note (0) | 2020.08.30 |
NX-bit binary exploit ( with ASLR ) (0) | 2020.08.27 |
NX-bit binary exploit (0) | 2020.08.25 |