These write ups don't include any exploit codes but just EIP control.
tenement
Given binary 'tenement' is x86 stripped elf file, too.
1 2 | zero@ubuntu:~/Desktop/ctf/plaid2014$ file tenement tenement: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, stripped | cs |
And applied memory protections are...
1 2 3 4 5 6 7 8 | zero@ubuntu:~/Desktop/ctf/plaid2014$ gdb -q ./tenement Reading symbols from ./tenement...(no debugging symbols found)...done. gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : disabled PIE : disabled RELRO : disabled | cs |
None!
But when i just execute binary, following error appears..
1 2 | zero@ubuntu:~/Desktop/ctf/plaid2014$ ./tenement ./tenement: error while loading shared libraries: libseccomp.so.2: cannot open shared object file: No such file or directory | cs |
Above lib error could be resolved with installing...
- libseccomp : libseccomp2_2.1.0+dfsg-1_i386.deb
- libjansson : libjansson4_2.2.1-1_386.deb
After installing all of them, we can see the following message when trying to run it.
1 2 | zero@ubuntu:~/Desktop/ctf/plaid2014$ ./tenement USAGE: ./tenement CONFIG | cs |
Does It mean 'CONFIG' file is needed?
After some inspections, i can find about CONFIG and kind of AUTH.
First, Load a CONFIG file and it needs to be 'json' type.
Second, parsing elements string 'key's value and integer 'addrs's value.
Especially, 'addrs's value is used when allocating memory with mmap(). ( size is 0x4000 )
1 2 3 4 5 6 7 8 9 10 11 12 | v1 = json_load_file(CONFIG, 0, &v23); v20 = v1; if ( v1 ) { v4 = json_object_get(v1, &key, v2, v2); ... if ( snprintf((char *)v9, v8, "%s%s", "pppp: ", v5) >= 0 ) { sub_8048A4D(); for ( i = 0; i <= 3; ++i ) *((_BYTE *)ptr + i) -= 32; v10 = json_object_get(v20, "addrs", i, i); | cs |
And we could see the flag format from above ( pppp:'flag' )
Then all we have to do is making a shellcode which works as finding 'pppp' in memory,
There is stack overflow bug at 0x8048dc1. just simply found..
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 | .text:08048DC1 vuln proc near ; CODE XREF: main+66p .text:08048DC1 .text:08048DC1 buf = byte ptr -88h .text:08048DC1 var_4 = dword ptr -4 .text:08048DC1 .text:08048DC1 push ebp .text:08048DC2 xor eax, eax .text:08048DC4 mov ebp, esp .text:08048DC6 or ecx, 0FFFFFFFFh .text:08048DC9 push edi .text:08048DCA sub esp, 88h .text:08048DD0 mov edx, buf .text:08048DD6 mov edi, edx .text:08048DD8 repne scasb .text:08048DDA lea edi, [ebp+buf] .text:08048DE0 not ecx .text:08048DE2 dec ecx .text:08048DE3 push ecx ; n .text:08048DE4 push edx ; buf .text:08048DE5 push 1 ; fd .text:08048DE7 call _write .text:08048DEC add esp, 0Ch .text:08048DEF push 128 ; nbytes .text:08048DF4 push edi ; buf .text:08048DF5 push 0 ; fd .text:08048DF7 call _read .text:08048DFC call edi .text:08048DFE add esp, 10h .text:08048E01 mov edi, [ebp+var_4] .text:08048E04 leave .text:08048E05 retn | cs |
We have 128 bytes to write on stdin.
Final exploit is..
1. making a shellcode finding 'pppp' on memory. Of course its size has to smaler than 128 bytes.
-> The reason finding 'pppp' on memory is next to string 'pppp', there is 'FLAG'
2. just send it...
------------ Skip below progress because i don't know exact server environment,,,
sass
Given file is x86 elf binary.
1 2 | zero@ubuntu:~/Desktop/ctf/plaid2014$ file ./sass ./sass: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, not stripped | cs |
Applied memory protections are..
1 2 3 4 5 6 7 8 | zero@ubuntu:~/Desktop/ctf/plaid2014$ gdb -q ./sass Reading symbols from ./sass...(no debugging symbols found)...done. gdb-peda$ checksec CANARY : disabled FORTIFY : ENABLED NX : ENABLED PIE : ENABLED RELRO : Partial | cs |
There are PIE, NX, FORTIFY but canary. Also ASLR is full on my env.
This binary only has 2 functions, main() and read_numbers().
In main(),
read numbers from stdin with read_numbers(). then, qsort() ( qucik sort ) and print all of them.
In read_numbers func(),
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | int __cdecl read_numbers(int a1) { int v1; // ebp@1 char v2; // di@1 int res; // esi@1 ssize_t input_size; // eax@2 char *start; // edx@3 int buf[i]; // eax@3 char *end; // [sp+14h] [bp-1028h]@3 char v9; // [sp+1Ah] [bp-1022h]@1 char v10; // [sp+1Bh] [bp-1021h]@1 char v11[4124]; // [sp+20h] [bp-101Ch]@2 v1 = 0; v2 = 0; res = 0; v10 = 0; v9 = 0; LABEL_2: input_size = read(0, v11, 4096u); if ( input_size <= 0 ) __assert_fail("bytesread > 0", "sass.c", 0x1Bu, "read_numbers"); start = v11; end = &v11[input_size]; buf[i] = v11[0]; if ( v11[0] > '9' ) goto LABEL_13; while ( 1 ) { if ( buf[i] >= 48 ) { res = res * (v9 < 1u ? 10 : 16) + buf[i] - 48; goto LABEL_10; } if ( buf[i] != 10 ) { if ( buf[i] <= 10 ) { if ( buf[i] != 9 ) goto LABEL_28; } else if ( buf[i] != 32 ) { if ( buf[i] == 45 ) { v10 = 1; goto LABEL_10; } LABEL_28: __assert_fail("!\"Bad input.\"", "sass.c", 0x3Cu, "read_numbers"); } goto LABEL_19; } if ( v2 ) return v1; v2 = 1; LABEL_19: v9 = 0; if ( v10 ) res = -res; *(a1 + 4 * v1++) += res; res = 0; if ( buf[i] != 10 ) goto LABEL_10; while ( 2 ) { if ( ++start == end ) goto LABEL_2; buf[i] = *start; if ( buf[i] > '9' ) { LABEL_13: if ( buf[i] > 'f' ) { if ( buf[i] != 'x' ) goto LABEL_28; v9 = 1; } else if ( buf[i] >= 'a' ) { res = 16 * res + buf[i] - 'W'; } else { if ( (buf[i] - 'A') > 5u ) goto LABEL_28; res = 16 * res + buf[i] - '7'; } LABEL_10: v2 = 0; continue; } break; } } } // Hey-rayed codes are so dirty. Let's beautify that codes. int read_numbers(int *num) { int cnt = 0; int number = 0; bool IsHex = false; // Check is there 'x' in '0x????' bool IsNewline = false; // Check '\n' bool IsNegative = false; // Check is number negative char buff[4096] = {0, }; for(;;) { int size = read(0, buf, 4096); assert(size > 0); for(int i = 0; i < size; ++i) { switch(buf[i]) { case '0'~'9': number *= IsHex ? 16 : 10 + buf[i] - '0'; break; case 'A'~'F': number *= 16; number += buf[i] - 'A' + 10; break; case 'a'~'f': number *= 16; number += buf[i] - 'a' + 10; break; case 'x': IsHex = true; break; case '\n': if(IsNewline) return cnt; else IsNewline = true; break; case '-': IsNegative = true; break; case ' '~'\t': IsHex= false; num[cnt] += IsNegative ? -number : number; number = 0; ++cnt; break; default: assert("!Bad input."); break; } if(buf[i] != '\n') IsNewline = false; } } } // Actually there is no '~' grammar in switch~case but i use for convince :). | cs |
Just works as really reading number. if number is hex format, chagne to dec type.
The problem is... i think there is no leaking verctor. Even as i know, specific libc version isn't given too.
which means, this chal may be solved on server's local env and ALSR would be partialy(?) disabled.
Anyway, let's find exploit vector to overwrite ret with system() for ROP or RTL, etc..
Then i found there is buffer overflow at 40s input and control EIP successfully.
1 2 3 4 5 6 | zero@ubuntu:~/Desktop/ctf/plaid2014$ gdb -q ./sass core Reading symbols from ./sass...(no debugging symbols found)...done. [New LWP 7599] Core was generated by `./sass'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x41414141 in ?? () | cs |
But my env ( ubuntu 16.04 ) is ASLR-FULL and i can't find any leaking vector on binary.
Which means exploit would be proceeded unless ALSR is disabled. ( i can disable ASLR but i didn't do it :) for my laziness ...)
Despite disabling ASLR, kind of brute-force is needed because libc base address is changed by PIE.
Anyway, after disabling ASLR, RTL would be worked. Try it yourself!
'CTFs > Plaid 2014' 카테고리의 다른 글
[Plaid 2014] pwnable : kappa (0) | 2016.08.27 |
---|---|
[Plaid 2014] pwnable : ezhp (0) | 2016.08.27 |
[Plaid 2014] reversing : hudak (0) | 2016.08.27 |
[Plaid 2014] forensic : zfs (0) | 2016.08.27 |
[Plaid 2014] forensic : rsa (0) | 2016.08.27 |