bomb lab phase 2~6

자 계속 해보자.

깔끔한 솔루션이 아닌 정말로 어떻게 이것저것 해보면서 해결을 해왔는지를 다루고있다.

삽질기

여기서 어셈관련한것을 보면서 진행하고있다.

phase_2

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
(gdb) disas phase_2
Dump of assembler code for function phase_2:
   0x0000000000400ea9 <+0>:	push   %rbp
   0x0000000000400eaa <+1>:	push   %rbx
   0x0000000000400eab <+2>:	sub    $0x28,%rsp
   0x0000000000400eaf <+6>:	mov    %fs:0x28,%rax
   0x0000000000400eb8 <+15>:	mov    %rax,0x18(%rsp)
   0x0000000000400ebd <+20>:	xor    %eax,%eax
   0x0000000000400ebf <+22>:	mov    %rsp,%rsi
   0x0000000000400ec2 <+25>:	callq  0x40143e <read_six_numbers>
   0x0000000000400ec7 <+30>:	cmpl   $0x0,(%rsp)
   0x0000000000400ecb <+34>:	jns    0x400ed2 <phase_2+41>
   0x0000000000400ecd <+36>:	callq  0x40141c <explode_bomb>
   0x0000000000400ed2 <+41>:	mov    %rsp,%rbp
   0x0000000000400ed5 <+44>:	mov    $0x1,%ebx
   0x0000000000400eda <+49>:	mov    %ebx,%eax
   0x0000000000400edc <+51>:	add    0x0(%rbp),%eax
   0x0000000000400edf <+54>:	cmp    %eax,0x4(%rbp)
   0x0000000000400ee2 <+57>:	je     0x400ee9 <phase_2+64>
   0x0000000000400ee4 <+59>:	callq  0x40141c <explode_bomb>
   0x0000000000400ee9 <+64>:	add    $0x1,%ebx
   0x0000000000400eec <+67>:	add    $0x4,%rbp
   0x0000000000400ef0 <+71>:	cmp    $0x6,%ebx
   0x0000000000400ef3 <+74>:	jne    0x400eda <phase_2+49>
   0x0000000000400ef5 <+76>:	mov    0x18(%rsp),%rax
   0x0000000000400efa <+81>:	xor    %fs:0x28,%rax
   0x0000000000400f03 <+90>:	je     0x400f0a <phase_2+97>
   0x0000000000400f05 <+92>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x0000000000400f0a <+97>:	add    $0x28,%rsp
   0x0000000000400f0e <+101>:	pop    %rbx
   0x0000000000400f0f <+102>:	pop    %rbp
   0x0000000000400f10 <+103>:	retq   
End of assembler dump.

제일 먼저 눈에 띄는건 bomb를 두번 부른다.

  • cmpl : 두값을 비교 뒤에값에 앞의 값을 뺀다. 여기서는 (%rsp) 값이 음수인지 체크
  • jns : 음수가 아니면 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(gdb) 
Dump of assembler code for function read_six_numbers:
   0x000000000040143e <+0>:	sub    $0x8,%rsp
   0x0000000000401442 <+4>:	mov    %rsi,%rdx
   0x0000000000401445 <+7>:	lea    0x4(%rsi),%rcx
   0x0000000000401449 <+11>:	lea    0x14(%rsi),%rax
   0x000000000040144d <+15>:	push   %rax
   0x000000000040144e <+16>:	lea    0x10(%rsi),%rax
   0x0000000000401452 <+20>:	push   %rax
   0x0000000000401453 <+21>:	lea    0xc(%rsi),%r9
   0x0000000000401457 <+25>:	lea    0x8(%rsi),%r8
   0x000000000040145b <+29>:	mov    $0x4025a3,%esi
   0x0000000000401460 <+34>:	mov    $0x0,%eax
   0x0000000000401465 <+39>:	callq  0x400bb0 <__isoc99_sscanf@plt>
   0x000000000040146a <+44>:	add    $0x10,%rsp
   0x000000000040146e <+48>:	cmp    $0x5,%eax
   0x0000000000401471 <+51>:	jg     0x401478 <read_six_numbers+58>
   0x0000000000401473 <+53>:	callq  0x40141c <explode_bomb>
   0x0000000000401478 <+58>:	add    $0x8,%rsp
   0x000000000040147c <+62>:	retq   
End of assembler dump.

read_six_number를 보면 cmp $0x5,%eax 에서 5보다 큰지를 비교하고있다. 문자열을 대충 넣어보니 eax 값이 0이고 1235678을 넣으니 1이된다 1 2 3 4 5 6 7 8 을 넣어보니 6이 된다. 숫자를 6까지 읽는 듯하다. 그뒤의 read_six_numbers를 나오고 나서 rsp에 저장된 값을 봤더니

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
(gdb) disas phase_2
Dump of assembler code for function phase_2:
   0x0000000000400ea9 <+0>:	push   %rbp
   0x0000000000400eaa <+1>:	push   %rbx
   0x0000000000400eab <+2>:	sub    $0x28,%rsp
   0x0000000000400eaf <+6>:	mov    %fs:0x28,%rax
   0x0000000000400eb8 <+15>:	mov    %rax,0x18(%rsp)
   0x0000000000400ebd <+20>:	xor    %eax,%eax
   0x0000000000400ebf <+22>:	mov    %rsp,%rsi
   0x0000000000400ec2 <+25>:	callq  0x40143e <read_six_numbers>
=> 0x0000000000400ec7 <+30>:	cmpl   $0x0,(%rsp)
   0x0000000000400ecb <+34>:	jns    0x400ed2 <phase_2+41>
   0x0000000000400ecd <+36>:	callq  0x40141c <explode_bomb>
   0x0000000000400ed2 <+41>:	mov    %rsp,%rbp
   0x0000000000400ed5 <+44>:	mov    $0x1,%ebx
   0x0000000000400eda <+49>:	mov    %ebx,%eax
   0x0000000000400edc <+51>:	add    0x0(%rbp),%eax
   0x0000000000400edf <+54>:	cmp    %eax,0x4(%rbp)
   0x0000000000400ee2 <+57>:	je     0x400ee9 <phase_2+64>
   0x0000000000400ee4 <+59>:	callq  0x40141c <explode_bomb>
   0x0000000000400ee9 <+64>:	add    $0x1,%ebx
   0x0000000000400eec <+67>:	add    $0x4,%rbp
   0x0000000000400ef0 <+71>:	cmp    $0x6,%ebx
   0x0000000000400ef3 <+74>:	jne    0x400eda <phase_2+49>
   0x0000000000400ef5 <+76>:	mov    0x18(%rsp),%rax
   0x0000000000400efa <+81>:	xor    %fs:0x28,%rax
   0x0000000000400f03 <+90>:	je     0x400f0a <phase_2+97>
   0x0000000000400f05 <+92>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x0000000000400f0a <+97>:	add    $0x28,%rsp
   0x0000000000400f0e <+101>:	pop    %rbx
   0x0000000000400f0f <+102>:	pop    %rbp
   0x0000000000400f10 <+103>:	retq   
End of assembler dump.
(gdb) info reg
rax            0x6	6
rbx            0x0	0
rcx            0x0	0
rdx            0x7fffffffde64	140737488346724
rsi            0x0	0
rdi            0x7fffffffd7c0	140737488345024
rbp            0x4021d0	0x4021d0 <__libc_csu_init>
rsp            0x7fffffffde50	0x7fffffffde50
r8             0x0	0
r9             0x0	0
r10            0x7ffff7b82f20	140737349431072
r11            0x4025b4	4203956
r12            0x400c60	4197472
r13            0x7fffffffdf70	140737488346992
r14            0x0	0
r15            0x0	0
rip            0x400ec7	0x400ec7 <phase_2+30>
eflags         0x206	[ PF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
(gdb) x/s $rsp
0x7fffffffde50:	"\001"
(gdb) x/x $rsp
0x7fffffffde50:	0x01

1이 저장되어있는걸로 봐서는 처음에 입력한 1을 가지고 비교를 하는 듯하다. 그럼 처음 숫자는 0이 들어가야한다. 이제부턴 값을 하나씩 비교하지 않을까란 생각을 하며 밑의 어셈들을 쭉 해석하기 시작했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0x0000000000400ed2 <+41>:	mov    %rsp,%rbp
0x0000000000400ed5 <+44>:	mov    $0x1,%ebx
0x0000000000400eda <+49>:	mov    %ebx,%eax
0x0000000000400edc <+51>:	add    0x0(%rbp),%eax
0x0000000000400edf <+54>:	cmp    %eax,0x4(%rbp)
0x0000000000400ee2 <+57>:	je     0x400ee9 <phase_2+64>
0x0000000000400ee4 <+59>:	callq  0x40141c <explode_bomb>
0x0000000000400ee9 <+64>:	add    $0x1,%ebx
0x0000000000400eec <+67>:	add    $0x4,%rbp
0x0000000000400ef0 <+71>:	cmp    $0x6,%ebx
0x0000000000400ef3 <+74>:	jne    0x400eda <phase_2+49>
0x0000000000400ef5 <+76>:	mov    0x18(%rsp),%rax
0x0000000000400efa <+81>:	xor    %fs:0x28,%rax
0x0000000000400f03 <+90>:	je     0x400f0a <phase_2+97>
0x0000000000400f05 <+92>:	callq  0x400b00 <__stack_chk_fail@plt>
0x0000000000400f0a <+97>:	add    $0x28,%rsp
0x0000000000400f0e <+101>:	pop    %rbx
0x0000000000400f0f <+102>:	pop    %rbp
1
2
3
4
5
6
rbp = rsp
ebx = 1
eax = ebx
eax += rbp(=0이어야함)
비교 : eax, *(rbp+4)
je : ZF: Zero flag. 가장 최근 연산의 결과가 0 것을 표시.

두번째값은 1

1
2
3
ebx += 1
rbp += 4(*rbp = 1)
cmp 6, ebx

여기서 이상함을 느낌. ebx는 2인 고정값인데 비교를 하기때문

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
(gdb) b *0x0000000000400ef0
Breakpoint 3 at 0x400ef0
(gdb) c
Continuing.

Breakpoint 3, 0x0000000000400ef0 in phase_2 ()
(gdb) disas phase_2
Dump of assembler code for function phase_2:
   0x0000000000400ea9 <+0>:	push   %rbp
   0x0000000000400eaa <+1>:	push   %rbx
   0x0000000000400eab <+2>:	sub    $0x28,%rsp
   0x0000000000400eaf <+6>:	mov    %fs:0x28,%rax
   0x0000000000400eb8 <+15>:	mov    %rax,0x18(%rsp)
   0x0000000000400ebd <+20>:	xor    %eax,%eax
   0x0000000000400ebf <+22>:	mov    %rsp,%rsi
   0x0000000000400ec2 <+25>:	callq  0x40143e <read_six_numbers>
   0x0000000000400ec7 <+30>:	cmpl   $0x0,(%rsp)
   0x0000000000400ecb <+34>:	jns    0x400ed2 <phase_2+41>
   0x0000000000400ecd <+36>:	callq  0x40141c <explode_bomb>
   0x0000000000400ed2 <+41>:	mov    %rsp,%rbp
   0x0000000000400ed5 <+44>:	mov    $0x1,%ebx
   0x0000000000400eda <+49>:	mov    %ebx,%eax
   0x0000000000400edc <+51>:	add    0x0(%rbp),%eax
   0x0000000000400edf <+54>:	cmp    %eax,0x4(%rbp)
   0x0000000000400ee2 <+57>:	je     0x400ee9 <phase_2+64>
   0x0000000000400ee4 <+59>:	callq  0x40141c <explode_bomb>
   0x0000000000400ee9 <+64>:	add    $0x1,%ebx
   0x0000000000400eec <+67>:	add    $0x4,%rbp
=> 0x0000000000400ef0 <+71>:	cmp    $0x6,%ebx
   0x0000000000400ef3 <+74>:	jne    0x400eda <phase_2+49>
   0x0000000000400ef5 <+76>:	mov    0x18(%rsp),%rax
   0x0000000000400efa <+81>:	xor    %fs:0x28,%rax
   0x0000000000400f03 <+90>:	je     0x400f0a <phase_2+97>
   0x0000000000400f05 <+92>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x0000000000400f0a <+97>:	add    $0x28,%rsp
   0x0000000000400f0e <+101>:	pop    %rbx
   0x0000000000400f0f <+102>:	pop    %rbp
   0x0000000000400f10 <+103>:	retq   
End of assembler dump.
(gdb) info reg
rax            0x1	1
rbx            0x2	2
rcx            0x0	0
rdx            0x7fffffffde64	140737488346724
rsi            0x0	0
rdi            0x7fffffffd7c0	140737488345024
rbp            0x7fffffffde54	0x7fffffffde54
rsp            0x7fffffffde50	0x7fffffffde50
r8             0x0	0
r9             0x0	0
r10            0x7ffff7b82f20	140737349431072
r11            0x4025b4	4203956
r12            0x400c60	4197472
r13            0x7fffffffdf70	140737488346992
r14            0x0	0
r15            0x0	0
rip            0x400ef0	0x400ef0 <phase_2+71>
eflags         0x202	[ IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0

생각한 2가 맞게나온다 아 이값은 6일때까지 반복하는 loop 문임을 눈치챔 ebx 는 1씩 계속 올라가며 반복을 함. rbp의 포인터도 4씩 올라가면서 계속 만남.

반복하는 부분

1
2
3
4
5
6
eax = ebx
eax += rbp
비교 : eax, *(rbp+4)
je : ZF: Zero flag. 가장 최근 연산의 결과가 0인 것을 표시.
ebx++
rbp +=4

여기서 앞의 rbp값을 더하고 ebx는 매차례 1씩더해지는 규칙임을 눈치챔

answer 0 1 3 6 10 15

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
40
(gdb) r
Starting program: /home/ubuntu/bomblab/bomb 
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
When a problem comes along, you must zip it!
Phase 1 defused. How about the next one?
0 1 3 6 10 15

Breakpoint 1, 0x0000000000400ea9 in phase_2 ()
(gdb) c
Continuing.

Breakpoint 2, 0x000000000040146e in read_six_numbers ()
(gdb) c
Continuing.

Breakpoint 3, 0x0000000000400ef0 in phase_2 ()
(gdb) c
Continuing.

Breakpoint 3, 0x0000000000400ef0 in phase_2 ()
(gdb) c
Continuing.

Breakpoint 3, 0x0000000000400ef0 in phase_2 ()
(gdb) c
Continuing.

Breakpoint 3, 0x0000000000400ef0 in phase_2 ()
(gdb) c
Continuing.

Breakpoint 3, 0x0000000000400ef0 in phase_2 ()
(gdb) c
Continuing.

Breakpoint 4, 0x0000000000400ef5 in phase_2 ()
(gdb) c
Continuing.
That's number 2.  Keep going!

fs가 어쩌고 나오는 초반 어셈은 나도 잘모르겠다

phase_3

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
40
41
42
43
44
45
(gdb) disas phase_3
Dump of assembler code for function phase_3:
   0x0000000000400f11 <+0>:	sub    $0x18,%rsp
   0x0000000000400f15 <+4>:	mov    %fs:0x28,%rax
   0x0000000000400f1e <+13>:	mov    %rax,0x8(%rsp)
   0x0000000000400f23 <+18>:	xor    %eax,%eax
   0x0000000000400f25 <+20>:	lea    0x4(%rsp),%rcx
   0x0000000000400f2a <+25>:	mov    %rsp,%rdx
   0x0000000000400f2d <+28>:	mov    $0x4025af,%esi
   0x0000000000400f32 <+33>:	callq  0x400bb0 <__isoc99_sscanf@plt>
   0x0000000000400f37 <+38>:	cmp    $0x1,%eax
   0x0000000000400f3a <+41>:	jg     0x400f41 <phase_3+48>
   0x0000000000400f3c <+43>:	callq  0x40141c <explode_bomb>
   0x0000000000400f41 <+48>:	cmpl   $0x7,(%rsp)
   0x0000000000400f45 <+52>:	ja     0x400f82 <phase_3+113>
   0x0000000000400f47 <+54>:	mov    (%rsp),%eax
   0x0000000000400f4a <+57>:	jmpq   *0x402420(,%rax,8)
   0x0000000000400f51 <+64>:	mov    $0x35c,%eax
   0x0000000000400f56 <+69>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f58 <+71>:	mov    $0x1a5,%eax
   0x0000000000400f5d <+76>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f5f <+78>:	mov    $0x357,%eax
   0x0000000000400f64 <+83>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f66 <+85>:	mov    $0x1a5,%eax
   0x0000000000400f6b <+90>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f6d <+92>:	mov    $0x1a5,%eax
   0x0000000000400f72 <+97>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f74 <+99>:	mov    $0x3bd,%eax
   0x0000000000400f79 <+104>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f7b <+106>:	mov    $0x3b1,%eax
   0x0000000000400f80 <+111>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f82 <+113>:	callq  0x40141c <explode_bomb>
   0x0000000000400f87 <+118>:	mov    $0x0,%eax
   0x0000000000400f8c <+123>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f8e <+125>:	mov    $0x302,%eax
   0x0000000000400f93 <+130>:	cmp    0x4(%rsp),%eax
   0x0000000000400f97 <+134>:	je     0x400f9e <phase_3+141>
   0x0000000000400f99 <+136>:	callq  0x40141c <explode_bomb>
   0x0000000000400f9e <+141>:	mov    0x8(%rsp),%rax
   0x0000000000400fa3 <+146>:	xor    %fs:0x28,%rax
   0x0000000000400fac <+155>:	je     0x400fb3 <phase_3+162>
   0x0000000000400fae <+157>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x0000000000400fb3 <+162>:	add    $0x18,%rsp
   0x0000000000400fb7 <+166>:	retq   
End of assembler dump.

explode_bomb 이 세번나온다. 보면 130줄로 계속 던지고 여기서 141로 던지고 여기서 162줄로 던져야 통과를 한다.

41줄에서 첫 검사 48에서 두번째 검사 57은 뭔지모르겠음 130줄로 던지기전에 eax에 계속 값을 넣고 여기서 rsp와 계속 비교를 한다.

마지막비교는 141에서 rsp+8을 rax로 넣고 rax와 fs:0x28(40)을 비교 같을때 ZF가 0이되고 155가 실행.

다시 차근차근 보기 시작하면 38줄에선 일단 한번만 입력을 받는다는걸 알 수 있다. 48에서는 점프를 하면안된다. rsp 는 7보다 작아야한다. jmpq가 수상하다

0x0000000000400f47 <+54>: mov (%rsp),%eax 0x0000000000400f4a <+57>: jmpq *0x402420(,%rax,8) 0x0000000000400f51 <+64>: mov $0x35c,%eax 0x0000000000400f56 <+69>: jmp 0x400f93 <phase_3+130>

일단 직접 실행시키면서 알아보기로 해봤다

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
(gdb) si
0x0000000000400f1e in phase_3 ()
(gdb) info reg
rax            0xf57be16096fb2000	-757764307315646464
rbx            0x0	0
rcx            0x1	1
rdx            0x603840	6305856
rsi            0x2	2
rdi            0x603840	6305856
rbp            0x4021d0	0x4021d0 <__libc_csu_init>
rsp            0x7fffffffde70	0x7fffffffde70
r8             0x604672	6309490
r9             0x7ffff7fe0540	140737354007872
r10            0x7ffff7fe0540	140737354007872
r11            0x246	582
r12            0x400c60	4197472
r13            0x7fffffffdf70	140737488346992
r14            0x0	0
r15            0x0	0
rip            0x400f1e	0x400f1e <phase_3+13>
eflags         0x202	[ IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0

%fs:0x28 의 값은 0xf57be16096fb2000 이다.

1
2
3
4
5
(gdb) si
0x0000000000400f23 in phase_3 ()
(gdb) x/3gx $rsp
0x7fffffffde70:	0x0000000000000000	0xf57be16096fb2000
0x7fffffffde80:	0x00007fffffffdf70
1
2
3
4
eax = 0
rcx = rsp+4
rdx = rsp
esi = $0x4025af

그후 대충보니 sscanf를 부르기위한 인자를 넣는거란걸 알고 sscanf뒷부분을 제대로 읽기 시작함.

41번째에서 반환값이 1과 같은지를 검사하고 rsp값이 7보다 큰지를 검사 작아야함 rsp

1
2
3
eax > 1
if *rsp < 7 jump
eax = *rsp

57번째에 점프할 주소를 가지고 점프후에 각 점프한 주소마다 특정한 eax값을 넣은후 130번째에서 맞는지 검사를 하는듯하다

7을 넣고나니 57에서 다음으로 jump를 한다.그뒤에는 eax와 rsp+4와 비교를 하는데 rsp + 4의 값이 두번째 인자로 넣은 값이라는 걸 직접 rsp로 이어지는 주소를 쭉 읽으니 알았다. 따라서 eax의 값이 두번째 인자가 되어야한다.

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
(gdb) disas phase_3
Dump of assembler code for function phase_3:
   0x0000000000400f11 <+0>:	sub    $0x18,%rsp
   0x0000000000400f15 <+4>:	mov    %fs:0x28,%rax
   0x0000000000400f1e <+13>:	mov    %rax,0x8(%rsp)
   0x0000000000400f23 <+18>:	xor    %eax,%eax
   0x0000000000400f25 <+20>:	lea    0x4(%rsp),%rcx
   0x0000000000400f2a <+25>:	mov    %rsp,%rdx
   0x0000000000400f2d <+28>:	mov    $0x4025af,%esi
   0x0000000000400f32 <+33>:	callq  0x400bb0 <__isoc99_sscanf@plt>
   0x0000000000400f37 <+38>:	cmp    $0x1,%eax
   0x0000000000400f3a <+41>:	jg     0x400f41 <phase_3+48>
   0x0000000000400f3c <+43>:	callq  0x40141c <explode_bomb>
   0x0000000000400f41 <+48>:	cmpl   $0x7,(%rsp)
   0x0000000000400f45 <+52>:	ja     0x400f82 <phase_3+113>
   0x0000000000400f47 <+54>:	mov    (%rsp),%eax
   0x0000000000400f4a <+57>:	jmpq   *0x402420(,%rax,8)
   0x0000000000400f51 <+64>:	mov    $0x35c,%eax
   0x0000000000400f56 <+69>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f58 <+71>:	mov    $0x1a5,%eax
   0x0000000000400f5d <+76>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f5f <+78>:	mov    $0x357,%eax
   0x0000000000400f64 <+83>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f66 <+85>:	mov    $0x1a5,%eax
   0x0000000000400f6b <+90>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f6d <+92>:	mov    $0x1a5,%eax
   0x0000000000400f72 <+97>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f74 <+99>:	mov    $0x3bd,%eax
   0x0000000000400f79 <+104>:	jmp    0x400f93 <phase_3+130>
=> 0x0000000000400f7b <+106>:	mov    $0x3b1,%eax
   0x0000000000400f80 <+111>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f82 <+113>:	callq  0x40141c <explode_bomb>
   0x0000000000400f87 <+118>:	mov    $0x0,%eax
   0x0000000000400f8c <+123>:	jmp    0x400f93 <phase_3+130>
   0x0000000000400f8e <+125>:	mov    $0x302,%eax
   0x0000000000400f93 <+130>:	cmp    0x4(%rsp),%eax
   0x0000000000400f97 <+134>:	je     0x400f9e <phase_3+141>
   0x0000000000400f99 <+136>:	callq  0x40141c <explode_bomb>
   0x0000000000400f9e <+141>:	mov    0x8(%rsp),%rax
   0x0000000000400fa3 <+146>:	xor    %fs:0x28,%rax
   0x0000000000400fac <+155>:	je     0x400fb3 <phase_3+162>
   0x0000000000400fae <+157>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x0000000000400fb3 <+162>:	add    $0x18,%rsp
   0x0000000000400fb7 <+166>:	retq   
End of assembler dump.
(gdb) info reg
rax            0x3b1	945
rbx            0x7fffffffdf78	140737488347000
rcx            0x0	0
rdx            0x7fffffffde74	140737488346740
rsi            0x0	0
rdi            0x7fffffffd800	140737488345088
rbp            0x4021d0	0x4021d0 <__libc_csu_init>
rsp            0x7fffffffde70	0x7fffffffde70
r8             0x0	0
r9             0x0	0
r10            0x7ffff7b82f20	140737349431072
r11            0x4025b4	4203956
r12            0x400c60	4197472
r13            0x7fffffffdf70	140737488346992
r14            0x0	0
r15            0x0	0
rip            0x400f80	0x400f80 <phase_3+111>
eflags         0x246	[ PF ZF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0

eax의 값은 945

7 945

phase_4

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
(gdb) disas phase_4
Dump of assembler code for function phase_4:
=> 0x0000000000400ff3 <+0>:	sub    $0x18,%rsp
   0x0000000000400ff7 <+4>:	mov    %fs:0x28,%rax
   0x0000000000401000 <+13>:	mov    %rax,0x8(%rsp)
   0x0000000000401005 <+18>:	xor    %eax,%eax
   0x0000000000401007 <+20>:	mov    %rsp,%rcx
   0x000000000040100a <+23>:	lea    0x4(%rsp),%rdx
   0x000000000040100f <+28>:	mov    $0x4025af,%esi
   0x0000000000401014 <+33>:	callq  0x400bb0 <__isoc99_sscanf@plt>
   0x0000000000401019 <+38>:	cmp    $0x2,%eax
   0x000000000040101c <+41>:	jne    0x401029 <phase_4+54>
   0x000000000040101e <+43>:	mov    (%rsp),%eax
   0x0000000000401021 <+46>:	sub    $0x2,%eax
   0x0000000000401024 <+49>:	cmp    $0x2,%eax
   0x0000000000401027 <+52>:	jbe    0x40102e <phase_4+59>
   0x0000000000401029 <+54>:	callq  0x40141c <explode_bomb>
   0x000000000040102e <+59>:	mov    (%rsp),%esi
   0x0000000000401031 <+62>:	mov    $0x6,%edi
   0x0000000000401036 <+67>:	callq  0x400fb8 <func4>
   0x000000000040103b <+72>:	cmp    0x4(%rsp),%eax
   0x000000000040103f <+76>:	je     0x401046 <phase_4+83>
   0x0000000000401041 <+78>:	callq  0x40141c <explode_bomb>
   0x0000000000401046 <+83>:	mov    0x8(%rsp),%rax
   0x000000000040104b <+88>:	xor    %fs:0x28,%rax
   0x0000000000401054 <+97>:	je     0x40105b <phase_4+104>
   0x0000000000401056 <+99>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x000000000040105b <+104>:	add    $0x18,%rsp
   0x000000000040105f <+108>:	retq   
End of assembler dump.

이번에는 바로 sscanf 뒤부터 살펴보려고한다. 입력이 단 2개여야하는것같다. 그뒤 eax에 rsp를 넣고 rsp는 (첫번째 입력값임을 phase_3 에서 알수있었다. 2를 빼고 2와 비교르르 한다. eax 는 unsinged로 2보다 작거나 같아야하는듯하다.그럼 후보는 2,3,4다. 그런데 rsp값을 보는데 반대로 저장되어있다 3 10을 넣으면 rsp주소에 10이 저장되어있더라 따라서 반대로 봐야함

rsp 를 다시 esi에 넣고 edi = 6를 넣고 call func4를 부른다. func4를 비교해야하는듯하다 여기서 나온 return 값과 두번째 인자가 같아야한다. 그후 세번째 인자도 들어간다. 그후 %fs:0x28과 비교해서 같으면 된다.

%fs:0x28은 phase_3에서 삽질하면서 발견했다 0xf57be16096fb2000 이다. 일단 func4로 들어가는 인자들을 정리하고 func4를 봐야할 듯 하다.

  • esi = rsp
  • edi = 6

각 레지스터가 첫번째 두번째 인자이니 이 두개만 func4에 들어가는듯하다

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
(gdb) disas func4
Dump of assembler code for function func4:
   0x0000000000400fb8 <+0>:	test   %edi,%edi
   0x0000000000400fba <+2>:	jle    0x400fe7 <func4+47>
=> 0x0000000000400fbc <+4>:	mov    %esi,%eax
   0x0000000000400fbe <+6>:	cmp    $0x1,%edi
   0x0000000000400fc1 <+9>:	je     0x400ff1 <func4+57>
   0x0000000000400fc3 <+11>:	push   %r12
   0x0000000000400fc5 <+13>:	push   %rbp
   0x0000000000400fc6 <+14>:	push   %rbx
   0x0000000000400fc7 <+15>:	mov    %esi,%ebp
   0x0000000000400fc9 <+17>:	mov    %edi,%ebx
   0x0000000000400fcb <+19>:	lea    -0x1(%rdi),%edi
   0x0000000000400fce <+22>:	callq  0x400fb8 <func4>
   0x0000000000400fd3 <+27>:	lea    0x0(%rbp,%rax,1),%r12d
   0x0000000000400fd8 <+32>:	lea    -0x2(%rbx),%edi
   0x0000000000400fdb <+35>:	mov    %ebp,%esi
   0x0000000000400fdd <+37>:	callq  0x400fb8 <func4>
   0x0000000000400fe2 <+42>:	add    %r12d,%eax
   0x0000000000400fe5 <+45>:	jmp    0x400fed <func4+53>
   0x0000000000400fe7 <+47>:	mov    $0x0,%eax
   0x0000000000400fec <+52>:	retq   
   0x0000000000400fed <+53>:	pop    %rbx
   0x0000000000400fee <+54>:	pop    %rbp
   0x0000000000400fef <+55>:	pop    %r12
   0x0000000000400ff1 <+57>:	repz retq 

edi는 0이아니므로 jle는 무조건 건너뛴다. *rsp값을 eax에 넣는다 그후 두번째 점프도 무시하고 esi, edi의 값을 ebo ebx에 넣는다. edi의 값을 rdi-1에 넣고 func4를 부른다. 아 재귀함수다. edi가 6이 들어갓으니 대충 6번은 적어도 돌겠지라는 생각을 할 수 있고 edi가 1일때 첫번째 재귀가 끝이난다. 굉장히 로직이 복잡하다. 여기까지는 rsp값이 리턴으로 나온다.

1
2
3
4
5
6
7
=> 0x0000000000400fd3 <+27>:	lea    0x0(%rbp,%rax,1),%r12d
   0x0000000000400fd8 <+32>:	lea    -0x2(%rbx),%edi
   0x0000000000400fdb <+35>:	mov    %ebp,%esi
   0x0000000000400fdd <+37>:	callq  0x400fb8 <func4>
   0x0000000000400fe2 <+42>:	add    %r12d,%eax
   0x0000000000400fe5 <+45>:	jmp    0x400fed <func4+53>
   0x0000000000400fe7 <+47>:	mov    $0x0,%eax

갑자기 rbp가 튀어나와 뭐지하고 ebp를 추적해보니 처음에 들어간 인자(두번째 입력한 인자값) esp-2로 저장 된다 즉 5번의 재귀동안 같은 값이 5번 들어가있다 rbx도 마찮가지로 살펴보니 ebx로서 각 단계의 edi값이 들어가있다 깊이순서로 6 5 4 3 2 1 이 들어가있다 그후

  • esi = rsp
  • edi = 6
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
Dump of assembler code for function func4:
<+0>:	test   %edi,%edi : edi == 0일때 eax 0으로하고 반환
<+2>:	jle    0x400fe7 <func4+47>
<+4>:	mov    %esi,%eax : eax = esi 
<+6>:	cmp    $0x1,%edi : edi == 1
<+9>:	je     0x400ff1 <func4+57>
<+11>:	push   %r12
<+13>:	push   %rbp
<+14>:	push   %rbx
<+15>:	mov    %esi,%ebp : ebp = esi
<+17>:	mov    %edi,%ebx : ebx = edi
<+19>:	lea    -0x1(%rdi),%edi : edi--
<+22>:	callq  0x400fb8 <func4>
<+27>:	lea    0x0(%rbp,%rax,1),%r12d : r12d = rdi + rsi
<+32>:	lea    -0x2(%rbx),%edi : edi = ebx - 2
<+35>:	mov    %ebp,%esi : esi = ebp
<+37>:	callq  0x400fb8 <func4>
<+42>:	add    %r12d,%eax : eax = r12d
<+45>:	jmp    0x400fed <func4+53>
<+47>:	mov    $0x0,%eax
<+52>:	retq   
<+53>:	pop    %rbx
<+54>:	pop    %rbp
<+55>:	pop    %r12
<+57>:	repz retq 

이이상 해석하기 짜증나서 그냥 반환값을 보기로했다 각각

  • 2 : 40
  • 3 : 60
  • 4 : 80

그냥 그대로 순서대로 넣었다. 정답이 세개다.

40 2

60 3

80 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(gdb) r
Starting program: /home/ubuntu/bomblab/bomb sol.txt
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
That's number 2.  Keep going!
Halfway there!
80 4

Breakpoint 1, 0x0000000000400ff3 in phase_4 ()
(gdb) c
Continuing.

Breakpoint 2, 0x000000000040103b in phase_4 ()
(gdb) c
Continuing.
So you got that one.  Try this one.

날먹으로 풀음..

phase 5

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
40
(gdb) disas phase_5
Dump of assembler code for function phase_5:
   0x0000000000401060 <+0>:	sub    $0x18,%rsp
   0x0000000000401064 <+4>:	mov    %fs:0x28,%rax
   0x000000000040106d <+13>:	mov    %rax,0x8(%rsp)
   0x0000000000401072 <+18>:	xor    %eax,%eax
   0x0000000000401074 <+20>:	lea    0x4(%rsp),%rcx
   0x0000000000401079 <+25>:	mov    %rsp,%rdx
   0x000000000040107c <+28>:	mov    $0x4025af,%esi
   0x0000000000401081 <+33>:	callq  0x400bb0 <__isoc99_sscanf@plt>
   0x0000000000401086 <+38>:	cmp    $0x1,%eax
   0x0000000000401089 <+41>:	jg     0x401090 <phase_5+48>
   0x000000000040108b <+43>:	callq  0x40141c <explode_bomb>
   0x0000000000401090 <+48>:	mov    (%rsp),%eax
   0x0000000000401093 <+51>:	and    $0xf,%eax
   0x0000000000401096 <+54>:	mov    %eax,(%rsp)
   0x0000000000401099 <+57>:	cmp    $0xf,%eax
   0x000000000040109c <+60>:	je     0x4010cd <phase_5+109>
   0x000000000040109e <+62>:	mov    $0x0,%ecx
   0x00000000004010a3 <+67>:	mov    $0x0,%edx
   0x00000000004010a8 <+72>:	add    $0x1,%edx
   0x00000000004010ab <+75>:	cltq   
   0x00000000004010ad <+77>:	mov    0x402460(,%rax,4),%eax
   0x00000000004010b4 <+84>:	add    %eax,%ecx
   0x00000000004010b6 <+86>:	cmp    $0xf,%eax
   0x00000000004010b9 <+89>:	jne    0x4010a8 <phase_5+72>
   0x00000000004010bb <+91>:	movl   $0xf,(%rsp)
   0x00000000004010c2 <+98>:	cmp    $0xf,%edx
---Type <return> to continue, or q <return> to quit---
   0x00000000004010c5 <+101>:	jne    0x4010cd <phase_5+109>
   0x00000000004010c7 <+103>:	cmp    0x4(%rsp),%ecx
   0x00000000004010cb <+107>:	je     0x4010d2 <phase_5+114>
   0x00000000004010cd <+109>:	callq  0x40141c <explode_bomb>
   0x00000000004010d2 <+114>:	mov    0x8(%rsp),%rax
   0x00000000004010d7 <+119>:	xor    %fs:0x28,%rax
   0x00000000004010e0 <+128>:	je     0x4010e7 <phase_5+135>
   0x00000000004010e2 <+130>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x00000000004010e7 <+135>:	add    $0x18,%rsp
   0x00000000004010eb <+139>:	retq   
End of assembler dump.

입력은 두개이상 받는다. 그다음 60 je에서는 조건을 만족할시에 bomb이 터진다. 89 jne에서는 위로 점프를 함으로서 루프를 돈다는걸 알아차렸다. 101 jne에서는 bomb으로 점프한다 107에서는 조건을 만족해야한다. 128 je도 만족해야한다. 48부터 어셈을 읽기 시작하자

  • rsp를 eax에 넣고 0xF와 and연산을 한다. 그후 다시 rsp에 저장 eax가 0xF와 같을시 bomb
  • ecx,edx = 0으로 루프시작 edx를 1씩 증가, mov 0x402460(,%rax,4),%eax, ecx += eax eax가 0xf에 도달할때까지 루프
  • rsp에 0xF저장 edx와 0xF를 비교 같아야함. ecx *(rsp+4)비교 같아야함.ecx는 루프에서 값이 정해짐

입력한값이 rsp에 어떻게 저장되는지를 알아봐야할것같다. 뒤집어서 들어가던건 리틀엔디안이라서 뒤집어서 저장되는 듯하다 10 20입력

1
2
3
(gdb) x/4gx $rsp
0x7fffffffde70:	0x000000140000000a	0x484aec3367598400
0x7fffffffde80:	0x00007fffffffdf70	0x0000000000400e65

loop문을 보는데 이상한 주솟값이 들어가있다. 이값을 직접 봐야할것같다. eax가 왔다갔다하면서 0xF가 될때까지 edx가 0xf가 되어야한다 총 15번 루프를 돌아야한다. 여기서 루프도는동안 총 eax합이 ecx값이 되고 이게 두번째 입력할 값이 되어야한다. eax가 15번 돌 첫 rax값을 이제 찾아야한다.

1
2
3
4
5
6
7
8
9
10
11
(gdb) x/50gx 0x402460
0x402460 <array.3597>:	0x000000020000000a	0x000000070000000e
0x402470 <array.3597+16>:	0x0000000c00000008	0x0000000b0000000f
0x402480 <array.3597+32>:	0x0000000400000000	0x0000000d00000001
0x402490 <array.3597+48>:	0x0000000900000003	0x0000000500000006
(gdb) x/16wx 0x402460
0x402460 <array.3597>:	0x0000000a	0x00000002	0x0000000e	0x00000007
0x402470 <array.3597+16>:	0x00000008	0x0000000c	0x0000000f	0x0000000b
0x402480 <array.3597+32>:	0x00000000	0x00000004	0x00000001	0x0000000d
0x402490 <array.3597+48>:	0x00000003	0x00000009	0x00000006	0x00000005

0에서 F까지 모든값이 들어가있다 여기서 eax가 0xf가 되기전까지 15번 돌도록 시작하는 번째를 찾으면 된다 노가다로 0xf가 되는 순서를 역으로 추척해가기로한다. 6 -> e -> 2 -> 1 -> a -> 0 -> 8 -> 4 -> 9 -> d -> b -> 7 -> 3 -> c -> 5 따라서 ecx값은 115이다.

5 115

1
2
3
4
5
6
7
8
9
10
(gdb) r
Starting program: /home/ubuntu/bomblab/bomb sol.txt
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
That's number 2.  Keep going!
Halfway there!
So you got that one.  Try this one.
5 115
Good work!  On to the next...

phase 6

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
(gdb) disas phase_6
Dump of assembler code for function phase_6:
   0x00000000004010ec <+0>:	push   %r13
   0x00000000004010ee <+2>:	push   %r12
   0x00000000004010f0 <+4>:	push   %rbp
   0x00000000004010f1 <+5>:	push   %rbx
   0x00000000004010f2 <+6>:	sub    $0x68,%rsp
   0x00000000004010f6 <+10>:	mov    %fs:0x28,%rax
   0x00000000004010ff <+19>:	mov    %rax,0x58(%rsp)
   0x0000000000401104 <+24>:	xor    %eax,%eax
   0x0000000000401106 <+26>:	mov    %rsp,%rsi
   0x0000000000401109 <+29>:	callq  0x40143e <read_six_numbers>
   0x000000000040110e <+34>:	mov    %rsp,%r12
   0x0000000000401111 <+37>:	mov    $0x0,%r13d
   0x0000000000401117 <+43>:	mov    %r12,%rbp
   0x000000000040111a <+46>:	mov    (%r12),%eax
   0x000000000040111e <+50>:	sub    $0x1,%eax
   0x0000000000401121 <+53>:	cmp    $0x5,%eax
   0x0000000000401124 <+56>:	jbe    0x40112b <phase_6+63>
   0x0000000000401126 <+58>:	callq  0x40141c <explode_bomb>
   0x000000000040112b <+63>:	add    $0x1,%r13d
   0x000000000040112f <+67>:	cmp    $0x6,%r13d
   0x0000000000401133 <+71>:	je     0x401172 <phase_6+134>
   0x0000000000401135 <+73>:	mov    %r13d,%ebx
---Type <return> to continue, or q <return> to quit---
   0x0000000000401138 <+76>:	movslq %ebx,%rax
   0x000000000040113b <+79>:	mov    (%rsp,%rax,4),%eax
   0x000000000040113e <+82>:	cmp    %eax,0x0(%rbp)
   0x0000000000401141 <+85>:	jne    0x401148 <phase_6+92>
   0x0000000000401143 <+87>:	callq  0x40141c <explode_bomb>
   0x0000000000401148 <+92>:	add    $0x1,%ebx
   0x000000000040114b <+95>:	cmp    $0x5,%ebx
   0x000000000040114e <+98>:	jle    0x401138 <phase_6+76>
   0x0000000000401150 <+100>:	add    $0x4,%r12
   0x0000000000401154 <+104>:	jmp    0x401117 <phase_6+43>
   0x0000000000401156 <+106>:	mov    0x8(%rdx),%rdx
   0x000000000040115a <+110>:	add    $0x1,%eax
   0x000000000040115d <+113>:	cmp    %ecx,%eax
   0x000000000040115f <+115>:	jne    0x401156 <phase_6+106>
   0x0000000000401161 <+117>:	mov    %rdx,0x20(%rsp,%rsi,2)
   0x0000000000401166 <+122>:	add    $0x4,%rsi
   0x000000000040116a <+126>:	cmp    $0x18,%rsi
   0x000000000040116e <+130>:	jne    0x401177 <phase_6+139>
   0x0000000000401170 <+132>:	jmp    0x40118b <phase_6+159>
   0x0000000000401172 <+134>:	mov    $0x0,%esi
   0x0000000000401177 <+139>:	mov    (%rsp,%rsi,1),%ecx
   0x000000000040117a <+142>:	mov    $0x1,%eax
   0x000000000040117f <+147>:	mov    $0x6032f0,%edx
---Type <return> to continue, or q <return> to quit---
   0x0000000000401184 <+152>:	cmp    $0x1,%ecx
   0x0000000000401187 <+155>:	jg     0x401156 <phase_6+106>
   0x0000000000401189 <+157>:	jmp    0x401161 <phase_6+117>
   0x000000000040118b <+159>:	mov    0x20(%rsp),%rbx
   0x0000000000401190 <+164>:	lea    0x20(%rsp),%rax
   0x0000000000401195 <+169>:	lea    0x48(%rsp),%rsi
   0x000000000040119a <+174>:	mov    %rbx,%rcx
   0x000000000040119d <+177>:	mov    0x8(%rax),%rdx
   0x00000000004011a1 <+181>:	mov    %rdx,0x8(%rcx)
   0x00000000004011a5 <+185>:	add    $0x8,%rax
   0x00000000004011a9 <+189>:	mov    %rdx,%rcx
   0x00000000004011ac <+192>:	cmp    %rsi,%rax
   0x00000000004011af <+195>:	jne    0x40119d <phase_6+177>
   0x00000000004011b1 <+197>:	movq   $0x0,0x8(%rdx)
   0x00000000004011b9 <+205>:	mov    $0x5,%ebp
   0x00000000004011be <+210>:	mov    0x8(%rbx),%rax
   0x00000000004011c2 <+214>:	mov    (%rax),%eax
   0x00000000004011c4 <+216>:	cmp    %eax,(%rbx)
   0x00000000004011c6 <+218>:	jge    0x4011cd <phase_6+225>
   0x00000000004011c8 <+220>:	callq  0x40141c <explode_bomb>
   0x00000000004011cd <+225>:	mov    0x8(%rbx),%rbx
   0x00000000004011d1 <+229>:	sub    $0x1,%ebp
   0x00000000004011d4 <+232>:	jne    0x4011be <phase_6+210>
   0x00000000004011d6 <+234>:	mov    0x58(%rsp),%rax
   0x00000000004011db <+239>:	xor    %fs:0x28,%rax
   0x00000000004011e4 <+248>:	je     0x4011eb <phase_6+255>
   0x00000000004011e6 <+250>:	callq  0x400b00 <__stack_chk_fail@plt>
   0x00000000004011eb <+255>:	add    $0x68,%rsp
   0x00000000004011ef <+259>:	pop    %rbx
   0x00000000004011f0 <+260>:	pop    %rbp
   0x00000000004011f1 <+261>:	pop    %r12
   0x00000000004011f3 <+263>:	pop    %r13
   0x00000000004011f5 <+265>:	retq   

엄청 길다. 차근차근 해보자 read_six_numbers 숫자 6개를 입력받는다. 직접 값을 넣어서 실행해보면서 분석해보기로했다. 1,2,3,4,5,6 in

info reg를 띄워보니 입력한 값들이 rsp가 가르키는 주소에 값이 저장되어있다.

1
2
rsp = r12 = rbp = eax
r13d = 0

rsp는 6이하. 읽다가 loop문임을 눈치챘다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0x0000000000401117 <+43>:	mov    %r12,%rbp
0x000000000040111a <+46>:	mov    (%r12),%eax
0x000000000040111e <+50>:	sub    $0x1,%eax
0x0000000000401121 <+53>:	cmp    $0x5,%eax
0x0000000000401124 <+56>:	jbe    0x40112b <phase_6+63>
0x0000000000401126 <+58>:	callq  0x40141c <explode_bomb>
0x000000000040112b <+63>:	add    $0x1,%r13d
0x000000000040112f <+67>:	cmp    $0x6,%r13d
0x0000000000401133 <+71>:	je     0x401172 <phase_6+134>
0x0000000000401135 <+73>:	mov    %r13d,%ebx
0x0000000000401138 <+76>:	movslq %ebx,%rax
0x000000000040113b <+79>:	mov    (%rsp,%rax,4),%eax
0x000000000040113e <+82>:	cmp    %eax,0x0(%rbp)
0x0000000000401141 <+85>:	jne    0x401148 <phase_6+92>
0x0000000000401143 <+87>:	callq  0x40141c <explode_bomb>
0x0000000000401148 <+92>:	add    $0x1,%ebx
0x000000000040114b <+95>:	cmp    $0x5,%ebx
0x000000000040114e <+98>:	jle    0x401138 <phase_6+76>
0x0000000000401150 <+100>:	add    $0x4,%r12
0x0000000000401154 <+104>:	jmp    0x401117 <phase_6+43>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rbp = r12(rsp)
eax = *r12
eax --
if 0x5 eax
jbe <=
r13d ++
r13d == 6 일때 탈출
---
rax = ebx = r13d 
eax = rsp + rax * 4
if eax rbp 
== bomb
ebx++
if 5 ebx  <= loop
----
r12 += 4
loop

첫번째 인풋값은 6보다 작아야한다. r13d는 루프번호 첫번째 루프는 6번 돈다. eax = r13d 번째 입력한 인풋값. 을 rbp : r12 : 일단 여기서는 첫번째 인자값 과 같으면 터진다. ebx를 ++하면서 루프를 돌린다. 그후엔 r12를 한칸올리면서 다시 전체 루프 모든 인풋값은 6보다 같거나 작아야한다. 이 이중루프문 전체는 그냥 이 넣은 인자값들이 같은것이 있는지 검사한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0x0000000000401156 <+106>:	mov    0x8(%rdx),%rdx
0x000000000040115a <+110>:	add    $0x1,%eax
0x000000000040115d <+113>:	cmp    %ecx,%eax
0x000000000040115f <+115>:	jne    0x401156 <phase_6+106>
0x0000000000401161 <+117>:	mov    %rdx,0x20(%rsp,%rsi,2)
0x0000000000401166 <+122>:	add    $0x4,%rsi
0x000000000040116a <+126>:	cmp    $0x18,%rsi
0x000000000040116e <+130>:	jne    0x401177 <phase_6+139>
0x0000000000401170 <+132>:	jmp    0x40118b <phase_6+159>
0x0000000000401172 <+134>:	mov    $0x0,%esi
0x0000000000401177 <+139>:	mov    (%rsp,%rsi,1),%ecx
0x000000000040117a <+142>:	mov    $0x1,%eax
0x000000000040117f <+147>:	mov    $0x6032f0,%edx
0x0000000000401184 <+152>:	cmp    $0x1,%ecx
0x0000000000401187 <+155>:	jg     0x401156 <phase_6+106>
0x0000000000401189 <+157>:	jmp    0x401161 <phase_6+117>

앞의 루프를 통과하면 코드가 134줄부터 시작한다.

1
2
3
4
5
esi = 0
ecx = rsp + rsi*1
eax = 1
edx = 0x6032f0
if 1 ecx  > label1  or label2

모르는 0x6032f0주소가 떳길래봤다 ecx = 첫번째 인자

1
2
3
4
5
6
7
(gdb)  x/50wx 0x6032f0
0x6032f0 <node1>:	0x00000079	0x00000001	0x00603300	0x00000000
0x603300 <node2>:	0x00000193	0x00000002	0x00603310	0x00000000
0x603310 <node3>:	0x00000096	0x00000003	0x00603320	0x00000000
0x603320 <node4>:	0x00000088	0x00000004	0x00603330	0x00000000
0x603330 <node5>:	0x000000d7	0x00000005	0x00603340	0x00000000
0x603340 <node6>:	0x000003a9	0x00000006	0x00000000	0x00000000

세상에 링크드리스트다.

1
2
3
4
5
6
7
8
9
10
11
12
13
label1:
   rdx = *(rdx+8)
   eax++
   if eax ecx != label1
label2:
   rsp + 0x20 + rsi*2 = rdx  //0x20(%rsp,%rsi,2)
   rsi += 4
   if rsi 0x18(=24) != label3, == break
label3:
   ecx = rsp + rsi
   eax = 1
   edx = 0x7032f0 
   if 1 ecx  > label1  or label2

label2에서 탈출하기위해서는 label2를 6번 반복해야한다. 0x20(%rsp,%rsi,2) 인 위치에 0x6032f0 + 8a를 저장한다

1
2
3
4
5
6
(gdb) x/20wx $rsp
0x7fffffffde00:	0x00000001	0x00000002	0x00000003	0x00000004
0x7fffffffde10:	0x00000005	0x00000006	0xf7dcfa00	0x00007fff
0x7fffffffde20:	0x006032f0	0x00000000	0x00603300	0x00000000
0x7fffffffde30:	0xffffdf70	0x00007fff	0x00000000	0x00000000
0x7fffffffde40:	0x00000000	0x00000000	0x004013ae	0x00000000

label1은 현재 ecx(n번째 입력한 인풋) 만큼 추가로 주솟값8을 더한다. 0x00603300 인것이 인풋이 2일때 label1을 두번돌아서 해당 값이 나왔다.

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
0x000000000040118b <+159>:	mov    0x20(%rsp),%rbx
0x0000000000401190 <+164>:	lea    0x20(%rsp),%rax
0x0000000000401195 <+169>:	lea    0x48(%rsp),%rsi
0x000000000040119a <+174>:	mov    %rbx,%rcx

0x000000000040119d <+177>:	mov    0x8(%rax),%rdx
0x00000000004011a1 <+181>:	mov    %rdx,0x8(%rcx)
0x00000000004011a5 <+185>:	add    $0x8,%rax
0x00000000004011a9 <+189>:	mov    %rdx,%rcx
0x00000000004011ac <+192>:	cmp    %rsi,%rax
0x00000000004011af <+195>:	jne    0x40119d <phase_6+177>

0x00000000004011b1 <+197>:	movq   $0x0,0x8(%rdx)
0x00000000004011b9 <+205>:	mov    $0x5,%ebp

0x00000000004011be <+210>:	mov    0x8(%rbx),%rax
0x00000000004011c2 <+214>:	mov    (%rax),%eax
0x00000000004011c4 <+216>:	cmp    %eax,(%rbx)
0x00000000004011c6 <+218>:	jge    0x4011cd <phase_6+225>
0x00000000004011c8 <+220>:	callq  0x40141c <explode_bomb>
0x00000000004011cd <+225>:	mov    0x8(%rbx),%rbx
0x00000000004011d1 <+229>:	sub    $0x1,%ebp
0x00000000004011d4 <+232>:	jne    0x4011be <phase_6+210>

0x00000000004011d6 <+234>:	mov    0x58(%rsp),%rax
0x00000000004011db <+239>:	xor    %fs:0x28,%rax
0x00000000004011e4 <+248>:	je     0x4011eb <phase_6+255>
0x00000000004011e6 <+250>:	callq  0x400b00 <__stack_chk_fail@plt>
0x00000000004011eb <+255>:	add    $0x68,%rsp
0x00000000004011ef <+259>:	pop    %rbx
0x00000000004011f0 <+260>:	pop    %rbp
0x00000000004011f1 <+261>:	pop    %r12
0x00000000004011f3 <+263>:	pop    %r13
0x00000000004011f5 <+265>:	retq   
1
2
3
4
5
6
7
8
9
10
rcx = = rbx = rax = rsp+0x20(=32)
rsi = rsp +0x48(72)
---
rcx + 8 = rdx = rax + 8
rax += 8
rcx = rdx 
if rax rsi != loop

rcx = rdx 
rax = rsi

rcx,rax에 전 label2에서 저장한 첫번째 주솟값들을 넣는다. rsi는 label2의 6번째 loop에 들어간 주솟값이다. rax를 한칸식 키우면서 6번째 값인 rsi와 rax가 같을때까지 루프를 돌린다.

1
2
3
4
5
6
7
8
rdx + 8 = 0
ebp = 5
---
eax = rax = rbx + 8
if eax rbx >= bomb 
rbx = rbx + 8
ebp--
ebp != 0 loop

값이 rbx > rbx +8 이렇게 정렬되어있어야함.

자 이제 최종적으로 입력값은 0x6032f0 의 주소에 따른 값이 내림차순이 되게 정렬하게 해야한다. 내림차순이 되기위해선 각각 차지하는 값들이 내림차순이 되게 label1에서 조정되게 값을 생각하면 된다.79, 193, 96, 88, d7, 399 이 내림차순이 되기 위해서는

6 2 5 3 4 1 을 입력하면 된다.

6 2 5 3 4 1

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
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ubuntu/bomblab/bomb sol.txt
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
That's number 2.  Keep going!
Halfway there!
So you got that one.  Try this one.
Good work!  On to the next...
6 2 5 3 4 1

Breakpoint 6, 0x00000000004011c4 in phase_6 ()
(gdb) c
Continuing.

Breakpoint 6, 0x00000000004011c4 in phase_6 ()
(gdb) c
Continuing.

Breakpoint 6, 0x00000000004011c4 in phase_6 ()
(gdb) c
Continuing.

Breakpoint 6, 0x00000000004011c4 in phase_6 ()
(gdb) c
Continuing.

Breakpoint 6, 0x00000000004011c4 in phase_6 ()
(gdb) c
Continuing.
Congratulations! You've defused the bomb!
[Inferior 1 (process 4015) exited normally]
(gdb) 

Posted 2020-08-10