Bomb lab
Let’s do reverse engineering
(Unfortunately, we cannot get CMU version bomb … We won’t lose points when the bomb blows up.)
Bomb lab how to
- read the writeup
- You get three files
- the README
- the executable
- the source file (Heavily redacted, you need to use
gdbto figure out the acutal code)
Useful utilities
objdump-dfor disassembly-tfor print the symbol table entries of the file
stringsto extract all printable stringsgdbto do the main jobmanto get the help you needreadelfto get read-only data section
(also IDA, Ghidra, radare2 and other reverse engineering tools, but you will lose your precious hand-on experience for reconstruct c code from assembly, not recommended.)
Get started
Gather information
There are 6 phases in the bomb
The bomb use
sscanfto get inputThe bomb can accept a command line argument and treat it as input, end with EOF and then switch to
stdin. So we can faciliate this feature to easy our pain of retyping.(Thank you Dr. Evil :crying_cat_face: )Although
objdump -dgives you a lot of information, it doesn’t tell you the whole story.For example
a call to
sscanfmight appear as:1
8048c36: e8 99 fc ff ff call 80488d4 <_init+0x1a0>
while in
gdbthis is1
0x000000000000075e <+68>: callq 0x5f0 <__isoc99_sscanf@plt>
(but I got the same result in
objdump)strings bombIt seems that there will be a secret stage :
Wow! You've defused the secret stage!ctrl-cdon’t work :So you think you can stop the bomb with ctrl-c, do you?(Laterly it turned out that
ctrl-cdoes not get banned:Well...OK. :-))It still try to connet to the server ? Let’s check the code to figure this out.
1
2
3
4
5
6greatwhite.ics.cs.cmu.edu
angelshark.ics.cs.cmu.edu
makoshark.ics.cs.cmu.edu
Error: HTTP request failed with error %d: %s
GET /%s/submitr.pl/?userid=%s&lab=%s&result=%s&submit=submit HTTP/1.0
Error: Unable to connect to server %scompile options
1
GNU C 4.8.1 -mtune=generic -march=x86-64 -ggdb -O1 -fstack-protector
(canary found)
less bomb.c- phase 4 has something to do with math
- phase 5 play with memory
- there must be a secret stage
objdump -t bombPotential useful symbols
1
2
3
4
5
6
7
8num_input_strings
explode_bomb
fun7
func4
string_length
secret_phase
strings_not_equal
read_six_numbersStatic analysis
1 | $ objdump -d bomb > codedump.s |
mainhas the same code shown bybomb.cnum_input_stringsis called byread_lineFunction
submitrtry to connect to the server, but it can only be called bydriver_post, anddriver_postdoesn’t called by any function. So the bomb won’t connect to CMU’s server when it explode.1
2$ readelf -x .rodata bomb
$ readelf -p .rodata bomb1
2
3
4
5
6
7
8000000000040143a <explode_bomb>:
40143a: 48 83 ec 08 sub $0x8,%rsp
40143e: bf a3 25 40 00 mov $0x4025a3,%edi
401443: e8 c8 f6 ff ff callq 400b10 <puts@plt>
401448: bf ac 25 40 00 mov $0x4025ac,%edi
40144d: e8 be f6 ff ff callq 400b10 <puts@plt>
401452: bf 08 00 00 00 mov $0x8,%edi
401457: e8 c4 f7 ff ff callq 400c20 <exit@plt>1
2
3
4
5
6void explode_bomb(void){
puts("BOOM!!!");
puts("The bomb has blown up.");
exit(8);
}
//no call to submitr() and driver_post()Phase 1
1
2
3
4
5
6
7
8
90000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 sub $0x8,%rsp
400ee4: be 00 24 40 00 mov $0x402400,%esi
400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal>
400eee: 85 c0 test %eax,%eax
400ef0: 74 05 je 400ef7 <phase_1+0x17>
400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>
400ef7: 48 83 c4 08 add $0x8,%rsp
400efb: c3 retq1
2
3
4
5
6
7
8void phase_1(char* input){
int esi = 0x402400;
//address at section .rodata
//Border relations with Canada have never been better.
int eax = strings_not_equal(input , (char*)esi);
if (eax != 0) explode_bomb();
return ;
}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
390000000000401338 <strings_not_equal>:
401338: 41 54 push %r12
40133a: 55 push %rbp
40133b: 53 push %rbx
40133c: 48 89 fb mov %rdi,%rbx
40133f: 48 89 f5 mov %rsi,%rbp
401342: e8 d4 ff ff ff callq 40131b <string_length>
401347: 41 89 c4 mov %eax,%r12d
40134a: 48 89 ef mov %rbp,%rdi
40134d: e8 c9 ff ff ff callq 40131b <string_length>
401352: ba 01 00 00 00 mov $0x1,%edx
401357: 41 39 c4 cmp %eax,%r12d
40135a: 75 3f jne 40139b <strings_not_equal+0x63>
40135c: 0f b6 03 movzbl (%rbx),%eax
40135f: 84 c0 test %al,%al
401361: 74 25 je 401388 <strings_not_equal+0x50>
401363: 3a 45 00 cmp 0x0(%rbp),%al
401366: 74 0a je 401372 <strings_not_equal+0x3a>
401368: eb 25 jmp 40138f <strings_not_equal+0x57>
40136a: 3a 45 00 cmp 0x0(%rbp),%al
40136d: 0f 1f 00 nopl (%rax)
401370: 75 24 jne 401396 <strings_not_equal+0x5e>
401372: 48 83 c3 01 add $0x1,%rbx
401376: 48 83 c5 01 add $0x1,%rbp
40137a: 0f b6 03 movzbl (%rbx),%eax
40137d: 84 c0 test %al,%al
40137f: 75 e9 jne 40136a <strings_not_equal+0x32>
401381: ba 00 00 00 00 mov $0x0,%edx
401386: eb 13 jmp 40139b <strings_not_equal+0x63>
401388: ba 00 00 00 00 mov $0x0,%edx
40138d: eb 0c jmp 40139b <strings_not_equal+0x63>
40138f: ba 01 00 00 00 mov $0x1,%edx
401394: eb 05 jmp 40139b <strings_not_equal+0x63>
401396: ba 01 00 00 00 mov $0x1,%edx
40139b: 89 d0 mov %edx,%eax
40139d: 5b pop %rbx
40139e: 5d pop %rbp
40139f: 41 5c pop %r12
4013a1: c3 retq1
2
3
4
5
6
7
8
9
10
11
12000000000040131b <string_length>:
40131b: 80 3f 00 cmpb $0x0,(%rdi)
40131e: 74 12 je 401332 <string_length+0x17>
401320: 48 89 fa mov %rdi,%rdx
401323: 48 83 c2 01 add $0x1,%rdx
401327: 89 d0 mov %edx,%eax
401329: 29 f8 sub %edi,%eax
40132b: 80 3a 00 cmpb $0x0,(%rdx)
40132e: 75 f3 jne 401323 <string_length+0x8>
401330: f3 c3 repz retq
401332: b8 00 00 00 00 mov $0x0,%eax
401337: c3 retq1
2
3
4
5
6
7
8
9
10int string_length(char * s){
if (s[0] == '\0') return 0;
char * rdx = s;
int res ;
do{
rdx++;
res = rdx - s;
}while(*rdx != '\0');
return res;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21int strings_not_equal(char * input , char * target){
int inputlen = string_length(input);
int targetlen = string_length(target);
int res = 1;
if ( inputlen != targetlen){ return res; }
else if (input[0] == '\0') {
res = 0;
return res;
}
else{
while (*input == *target){
input++;
target++;
if(*input == '\0'){
res = 0; return res;
}
}
res = 1;
return res;
}
}1
Phase 1 defused. How about the next one?
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
260000000000400efc <phase_2>:
400efc: 55 push %rbp
400efd: 53 push %rbx
400efe: 48 83 ec 28 sub $0x28,%rsp
400f02: 48 89 e6 mov %rsp,%rsi
400f05: e8 52 05 00 00 callq 40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)
400f0e: 74 20 je 400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 callq 40143a <explode_bomb>
400f15: eb 19 jmp 400f30 <phase_2+0x34>
400f17: 8b 43 fc mov -0x4(%rbx),%eax
400f1a: 01 c0 add %eax,%eax
400f1c: 39 03 cmp %eax,(%rbx)
400f1e: 74 05 je 400f25 <phase_2+0x29>
400f20: e8 15 05 00 00 callq 40143a <explode_bomb>
400f25: 48 83 c3 04 add $0x4,%rbx
400f29: 48 39 eb cmp %rbp,%rbx
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
400f2e: eb 0c jmp 400f3c <phase_2+0x40>
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
400f3a: eb db jmp 400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 add $0x28,%rsp
400f40: 5b pop %rbx
400f41: 5d pop %rbp
400f42: c3 retq1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18000000000040145c <read_six_numbers>:
40145c: 48 83 ec 18 sub $0x18,%rsp
401460: 48 89 f2 mov %rsi,%rdx
401463: 48 8d 4e 04 lea 0x4(%rsi),%rcx
401467: 48 8d 46 14 lea 0x14(%rsi),%rax
40146b: 48 89 44 24 08 mov %rax,0x8(%rsp)
401470: 48 8d 46 10 lea 0x10(%rsi),%rax
401474: 48 89 04 24 mov %rax,(%rsp)
401478: 4c 8d 4e 0c lea 0xc(%rsi),%r9
40147c: 4c 8d 46 08 lea 0x8(%rsi),%r8
401480: be c3 25 40 00 mov $0x4025c3,%esi
401485: b8 00 00 00 00 mov $0x0,%eax
40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt>
40148f: 83 f8 05 cmp $0x5,%eax
401492: 7f 05 jg 401499 <read_six_numbers+0x3d>
401494: e8 a1 ff ff ff callq 40143a <explode_bomb>
401499: 48 83 c4 18 add $0x18,%rsp
40149d: c3 retq1
2
3
4
5
6
7
8
9
10
11
12void read_six_numbers(char* input , int buf [6]){
int * rdx = buf;
int* rcx = buf + 1;
int * local1 = buf + 5;
int * local0 = buf + 4;
int * r9 = buf + 3;
int * r8 = buf + 2;
int res = sscanf(input , "%d %d %d %d %d %d" , rdx , rcx , r8 , r9 , local0 ,local1);
//On success, the function returns the number of items in the argument list successfully filled.
if (res > 5) return ;
else explode_bomb();
}1
2
3
4
5
6
7
8
9
10
11
12
13
14void phase_2(char * input){
int numbers [6] ;
read_six_numbers(char* input , numbers );
if(numbers[0] != 1) explode_bomb();
int* rbx = numbers + 1;
int* rbp = numbers + 6;
do{
int temp = (*(rbx-1))*2;
if (temp == *rbx )
rbx++;
else explode_bomb();
}while(rbp != rbx);
//1 2 4 8 16 32
}1
That's number 2. Keep going!
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
370000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub $0x18,%rsp
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
400f51: be cf 25 40 00 mov $0x4025cf,%esi
400f56: b8 00 00 00 00 mov $0x0,%eax
400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmp $0x1,%eax
400f63: 7f 05 jg 400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
400f6f: 77 3c ja 400fad <phase_3+0x6a>
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8) # use gdb
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov $0x0,%eax
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov $0x137,%eax
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9: 48 83 c4 18 add $0x18,%rsp
400fcd: c3 retq1
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/* .rodata
0x00402470 7c0f4000 00000000 b90f4000 00000000 |.@.......@.....
0x00402480 830f4000 00000000 8a0f4000 00000000 ..@.......@.....
0x00402490 910f4000 00000000 980f4000 00000000 ..@.......@.....
0x004024a0 9f0f4000 00000000 a60f4000 00000000 ..@.......@.....
*/
void phase_3(char * input){
int * temp1 = alloca(sizeof(int));
int * temp0 = alloca(sizeof(int));
int receive_cot = sscanf(input , "%d %d" , temp0 , temp1);
if (receive_cot > 1){
if ((unsigned int)*temp0 > 7u) {explode_bomb(); /* return 0;*/ }
else{
int res = *temp0;
switch(res){
case 0:
res = 207;break;
case 1:
res = 331;break;
case 2:
res = 707;break;
case 3:
res = 256;break;
case 4:
res = 389;break;
case 5:
res = 206;break;
case 6:
res = 682;break;
case 7:
res = 327;break;
}
if (res != *temp1) explode_bomb();
}
}
else explode_bomb();
}
/*
0 207
*/1
Halfway there!
Phase 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23000000000040100c <phase_4>:
40100c: 48 83 ec 18 sub $0x18,%rsp
401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
40101a: be cf 25 40 00 mov $0x4025cf,%esi
40101f: b8 00 00 00 00 mov $0x0,%eax
401024: e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02 cmp $0x2,%eax
40102c: 75 07 jne 401035 <phase_4+0x29>
40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)
401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 callq 40143a <explode_bomb>
40103a: ba 0e 00 00 00 mov $0xe,%edx
40103f: be 00 00 00 00 mov $0x0,%esi
401044: 8b 7c 24 08 mov 0x8(%rsp),%edi
401048: e8 81 ff ff ff callq 400fce <func4>
40104d: 85 c0 test %eax,%eax
40104f: 75 07 jne 401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp)
401056: 74 05 je 40105d <phase_4+0x51>
401058: e8 dd 03 00 00 callq 40143a <explode_bomb>
40105d: 48 83 c4 18 add $0x18,%rsp
401061: c3 retq1
2
3
4
5
6
7
8
9
10
11void phase_4(char* input){
int * temp1 = alloca(sizeof(int));
int * temp0 = alloca(sizeof(int));
int receiv = sscanf(input , "%d %d" , temp0 ,temp1);
if (receiv != 2) explode_bomb();
if (*temp0 > 14u ) explode_bomb();
int res = func4(*temp0 , 0 , 14);
if (res != 0) explode_bomb();
if (*temp1 != 0) explode_bomb();
return;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
230000000000400fce <func4>:
400fce: 48 83 ec 08 sub $0x8,%rsp
400fd2: 89 d0 mov %edx,%eax
400fd4: 29 f0 sub %esi,%eax
400fd6: 89 c1 mov %eax,%ecx
400fd8: c1 e9 1f shr $0x1f,%ecx
400fdb: 01 c8 add %ecx,%eax
400fdd: d1 f8 sar %eax
400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx
400fe2: 39 f9 cmp %edi,%ecx
400fe4: 7e 0c jle 400ff2 <func4+0x24>
400fe6: 8d 51 ff lea -0x1(%rcx),%edx
400fe9: e8 e0 ff ff ff callq 400fce <func4>
400fee: 01 c0 add %eax,%eax
400ff0: eb 15 jmp 401007 <func4+0x39>
400ff2: b8 00 00 00 00 mov $0x0,%eax
400ff7: 39 f9 cmp %edi,%ecx
400ff9: 7d 0c jge 401007 <func4+0x39>
400ffb: 8d 71 01 lea 0x1(%rcx),%esi
400ffe: e8 cb ff ff ff callq 400fce <func4>
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401007: 48 83 c4 08 add $0x8,%rsp
40100b: c3 retq1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18int func4(int temp0 , int esi, int edx){
int res = edx - esi;
res = res + ((unsigned int)res >> 31);
res >>= 1;
int local = res + esi;
if (local <= temp0){
res = 0;
if (local >= temp0) return res;
else {
return func4(temp0 , local + 1 , edx)* 2 + 1;
}
}
else{
edx = local - 1;
return func4(temp0 , esi , edx)*2;
}
}
//7 01
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
41
42
430000000000401062 <phase_5>:
401062: 53 push %rbx
401063: 48 83 ec 20 sub $0x20,%rsp
401067: 48 89 fb mov %rdi,%rbx
# get canary value
#40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
#401071: 00 00
#401073: 48 89 44 24 18 mov %rax,0x18(%rsp)
401078: 31 c0 xor %eax,%eax
40107a: e8 9c 02 00 00 callq 40131b <string_length>
40107f: 83 f8 06 cmp $0x6,%eax
401082: 74 4e je 4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 callq 40143a <explode_bomb>
401089: eb 47 jmp 4010d2 <phase_5+0x70>
40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx
40108f: 88 0c 24 mov %cl,(%rsp)
401092: 48 8b 14 24 mov (%rsp),%rdx
401096: 83 e2 0f and $0xf,%edx
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx
4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)
4010a4: 48 83 c0 01 add $0x1,%rax
4010a8: 48 83 f8 06 cmp $0x6,%rax
4010ac: 75 dd jne 40108b <phase_5+0x29>
4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp)
4010b3: be 5e 24 40 00 mov $0x40245e,%esi
4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal>
4010c2: 85 c0 test %eax,%eax
4010c4: 74 13 je 4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4010d0: eb 07 jmp 4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 mov $0x0,%eax
4010d7: eb b2 jmp 40108b <phase_5+0x29>
#check canary value
#4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax
#4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
#4010e5: 00 00
#4010e7: 74 05 je 4010ee <phase_5+0x8c>
#4010e9: e8 42 fa ff ff callq 400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 add $0x20,%rsp
4010f2: 5b pop %rbx
4010f3: c3 retq1
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
30void phase_5(char* input){
int inputlen = string_length(input);
char local [6];
if (inputlen == 6){
//Tag:
int rax = 0;
do{
char ecx = input[rax];
char rdx = ecx & 0xf;
char * addr = 0x4024b0;
//0x00 0x40 0x24 0xb0 0x6d 0x61 0x64 0x75 0x69 0x65 0x72 0x73 0x6e 0x66 0x6f 0x74 0x76 0x62 0x79 0x6c
//m a d u i e r s n f o t v b y l
rdx = *(addr + rdx);
local[rax] = rdx;
rax++;
while(rax != 6);
local[6] = '\0';
int res = strings_not_equal(local , 0x40245e);
//"flyers"
if (res != 0) explode_bomb();
}
else{
explode_bomb();
//goto Tag;
//the compiler generate some codes which will never be executed.
}
}
//9,f,e,5,6,7
//''.join([chr(0x40+i) for i in [9,0xf,0xe,5,6,7]])
//IONEFG1
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
83
84
85
86
87
8800000000004010f4 <phase_6>:
4010f4: 41 56 push %r14
4010f6: 41 55 push %r13
4010f8: 41 54 push %r12
4010fa: 55 push %rbp
4010fb: 53 push %rbx
4010fc: 48 83 ec 50 sub $0x50,%rsp
401100: 49 89 e5 mov %rsp,%r13
401103: 48 89 e6 mov %rsp,%rsi
401106: e8 51 03 00 00 callq 40145c <read_six_numbers>
40110b: 49 89 e6 mov %rsp,%r14
40110e: 41 bc 00 00 00 00 mov $0x0,%r12d
401114: 4c 89 ed mov %r13,%rbp
401117: 41 8b 45 00 mov 0x0(%r13),%eax
40111b: 83 e8 01 sub $0x1,%eax
40111e: 83 f8 05 cmp $0x5,%eax
401121: 76 05 jbe 401128 <phase_6+0x34>
401123: e8 12 03 00 00 callq 40143a <explode_bomb>
401128: 41 83 c4 01 add $0x1,%r12d
40112c: 41 83 fc 06 cmp $0x6,%r12d
401130: 74 21 je 401153 <phase_6+0x5f>
401132: 44 89 e3 mov %r12d,%ebx
401135: 48 63 c3 movslq %ebx,%rax
401138: 8b 04 84 mov (%rsp,%rax,4),%eax
40113b: 39 45 00 cmp %eax,0x0(%rbp)
40113e: 75 05 jne 401145 <phase_6+0x51>
401140: e8 f5 02 00 00 callq 40143a <explode_bomb>
401145: 83 c3 01 add $0x1,%ebx
401148: 83 fb 05 cmp $0x5,%ebx
40114b: 7e e8 jle 401135 <phase_6+0x41>
40114d: 49 83 c5 04 add $0x4,%r13
401151: eb c1 jmp 401114 <phase_6+0x20>
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi
401158: 4c 89 f0 mov %r14,%rax
40115b: b9 07 00 00 00 mov $0x7,%ecx
401160: 89 ca mov %ecx,%edx
401162: 2b 10 sub (%rax),%edx
401164: 89 10 mov %edx,(%rax)
401166: 48 83 c0 04 add $0x4,%rax
40116a: 48 39 f0 cmp %rsi,%rax
40116d: 75 f1 jne 401160 <phase_6+0x6c>
40116f: be 00 00 00 00 mov $0x0,%esi
401174: eb 21 jmp 401197 <phase_6+0xa3>
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx
40117a: 83 c0 01 add $0x1,%eax
40117d: 39 c8 cmp %ecx,%eax
40117f: 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 mov $0x6032d0,%edx
401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)
40118d: 48 83 c6 04 add $0x4,%rsi
401191: 48 83 fe 18 cmp $0x18,%rsi
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
40119a: 83 f9 01 cmp $0x1,%ecx
40119d: 7e e4 jle 401183 <phase_6+0x8f>
40119f: b8 01 00 00 00 mov $0x1,%eax
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx
4011a9: eb cb jmp 401176 <phase_6+0x82>
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax
4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi
4011ba: 48 89 d9 mov %rbx,%rcx
4011bd: 48 8b 10 mov (%rax),%rdx
4011c0: 48 89 51 08 mov %rdx,0x8(%rcx)
4011c4: 48 83 c0 08 add $0x8,%rax
4011c8: 48 39 f0 cmp %rsi,%rax
4011cb: 74 05 je 4011d2 <phase_6+0xde>
4011cd: 48 89 d1 mov %rdx,%rcx
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
4011d9: 00
4011da: bd 05 00 00 00 mov $0x5,%ebp
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax
4011e3: 8b 00 mov (%rax),%eax
4011e5: 39 03 cmp %eax,(%rbx)
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
4011f2: 83 ed 01 sub $0x1,%ebp
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 add $0x50,%rsp
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 retq1
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
83
84
85
86
87
88
89
90
91void phase_6(char* input){
int numbers[6];
int * walk = numbers;
read_six_numbers(input , numbers);
int * r14 = numbers;
int check_times = 0;
Loop:
int * rbp = walk;
if ( (*walk - 1) > 5u) { explode_bomb();}
check_times++;
if (check_times == 6){
//change numbers to (7 - origin number)
int * end = numbers+6;
int * p = numbers;
do{
*p = 7 - *p;
p++;
}
while( p != end);
//use memory value to update stack value
int index = 0; //rsi
while ((rcx = numbers[index]) <= 1){
int rdx = 0x6032d0;
Resume:
*(numbers + 8 + 2*index) = rdx; //write memory value to stack space
index++;
if (index == 6) {
int rbx = *(numbers+8); //6032d0
int * res = numbers+10; //6032e0
int * boundary = numbers + 20;
int rcx = *(numbers+8) ;
//write back value fetched from memory, beware of the order
do{
int rdx = *res;
*((long *)(rcx+0x8)) = rdx;
res+=2;
}
while(res != boundary , rcx = rdx);
//final 6 checks
*(rdx+0x8) = 0; //clear a chunk of memory
int cnt = 5; //rbp
do{
res = *((long *)rbx+0x8);
res = *res;
//compare stack value, *rbx, and memory value, res
if ( *rbx < res) { explode_bomb(); }
rbx = *(rbx+0x8);
cnt--;
}
while (cnt != 0 );
return;
}
}
//fetch a value from memory : *(0x6032d0 + 8*(rcx-1))
rax = 1;
rdx = 0x6032d0;
do{
rdx = *(rdx + 8);
//0x6032e0 //0x6032f0 //0x603300 //0x603310 //0x603320
rax++;
}
while(rax != rcx);
//offset (rcx - 1) times
goto Resume;
}
else{
//int rbx = r12;
int cot = check_times; // %ebx is the cot
do{
int next = numbers[cot];
if (*walk == next) { explode_bomb();}
cot++;
}while( cot <= 5);
walk ++;
goto Loop;
//every round of checking r13 points to next number
}
}
/*
1. every number - 1 should <= 5u
2. evry number should be different
*/Dynamic analysis for phase 6
1 | pwndbg> x /14gx 0x6032d0 |
1 | 0x6032d0 : 0x000000010000014c # value |
1 | pwndbg> x /12gx $rsp |
1 | pwndbg> x /12gx 0x6032d0 |
Correct C code
1 | void explode_bomb(); |
Correct layout of memory values
1 | # movl to retrive value from memory |
1 | Congratulations! You've defused the bomb! |
When working with low level codes the most important thing is patience.
Secret Phase
by examing the assembly code generated by objdump, we can see that there is a call to secret_phase in function phase_defused
1 | 00000000004015c4 <phase_defused>: |
What is num_input_strings ?
No codes named
num_input_stringin assemblySearch the symbols
1
2$ cat symbols | grep 'num_input_strings'
0000000000603760 g O .bss 0000000000000004 num_input_stringsBut what is
.bsssection ?1
2$ readelf -x .bss bomb
Section '.bss' has no data to dump.
1 |
|
1 | 0000000000401242 <secret_phase>: |
1 | void secret_phase(){ |
1 | 0000000000401204 <fun7>: |
1 | int fun7(int one, int two){ |
Once dump the memory 0x6030f0, I was surprised to find that this is a binary tree
1 | 0x6030f0 <n1>: 0x0000000000000024 0x0000000000603110 |
1 | ....36.... |
1 | //BST search for signal value |
I was so tired to think, so just write some shity code to solve the problem
1 | class BSTNode(object): |
1 | 0 when search : 8 |
Both 20 and 22 will do the favor for you
1 | Wow! You've defused the secret stage! |
End
1 | $ cat answer |