ASIS-ctf 2015 Leach
@mrexcessive WHA
The problem
Find the flag in this file. http://tasks.asis-ctf.ir/leach_bc83626319ab77ade5408f6ea222920e
The solution
Get file.
xz -d
file leach
chmod +x
OK so it bounces an ascii breakout around and says:
this may take too long time ... :) ############################## # # # # #| # # o # # # # |# # # # # ##############################
The game gets played by a forked thread...
Last write out from main thread is the "this may take too long time... :)" then nothing... but the ball bounces around from the cloned thread.
See http://linux.die.net/man/2/clone
Unlike fork(2), these calls allow the child process to share parts of its execution context with the calling process, such as the memory space, the table of file descriptors, and the table of signal handlers. (Note that on this manual page, "calling process" normally corresponds to "parent process". But see the description of CLONE_PARENT below.)
A function pointer is passed in to clone()
#define _GNU_SOURCE /* See feature_test_macros(7) */ #includeint clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ... /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
So ... do we just a) speed it up and b) fake the winning bats ?
No... the bats move by themselves. Is it just a timewaster ?
Hmmm... maybe outer thread sends keystrokes or something
$ readelf -a ./leach >elfread.txt
Doesnt' show any obvious input call...
What is being fetched at 0x4011f0 ?
4011dd: c7 05 11 1a 20 00 00 movl $0x0,0x201a11(%rip) # 602bf84011e4: 00 00 00 4011e7: 83 45 fc 01 addl $0x1,-0x4(%rbp) 4011eb: 8b 45 fc mov -0x4(%rbp),%eax 4011ee: 48 98 cltq 4011f0: 48 8b 04 c5 40 25 60 mov 0x602540(,%rax,8),%rax 4011f7: 00 4011f8: 48 89 45 e8 mov %rax,-0x18(%rbp) 4011fc: 48 83 7d e8 00 cmpq $0x0,-0x18(%rbp) 401201: 0f 85 1a ff ff ff jne 401121
Try patching - with bvi - end of game loop to exit not loop
00001070 1B 20 00 85 C0 0F 85* C7 FE FF FF C9 C3 55 48 89 . ...........UH.
change that x85 to x84 - now
401075: 0f 85 c7 fe ff ff jne 400f42# 0f84 would be je instead...
Just hangs.. so something checking timer ?
I wonder if inner game has to work.. or not ?
So just for confirmation that something inside matters:
401201: 0f 85 1a ff ff ff jne 401121# ^^^LOOP
Patch that one to je as well... then everything is complete.
OK that just exits...
Lets see if I can speed things up
Two places are:
********* inside the inner game thread ********* 400f42: bf 40 0d 03 00 mov $0x30d40,%edi ; usleep for 0x30d40 400f47: e8 54 fa ff ff callq 4009a0
and
********* outer loop ******* 401133: 8b 04 85 c0 29 60 00 mov 0x6029c0(,%rax,4),%eax 40113a: 89 c7 mov %eax,%edi # usleep something edi... 40113c: e8 3f f8 ff ff callq 400980# !! not micro-sleep ()
OK so the bats are moving to get in the way... maybe we need to make it lose ;)
Doesn't get to here...
4011a1: 8b 0c 85 00 23 60 00 mov 0x602300(,%rax,4),%ecx # read from table.. ?
Anyway...
Does it get to the sleep call.. and what value in there ?
401133: 8b 04 85 c0 29 60 00 mov 0x6029c0(,%rax,4),%eax 40113a: 89 c7 mov %eax,%edi # usleep something edi... 40113c: e8 3f f8 ff ff callq 400980# usleep () has 0x10cc... lots of seconds
Hmmm... maybe this is something then
(gdb) x/128xw 0x6029c0 0x6029c0: 0x000010cc 0x000010d1 0x000010d4 0x000010d8 0x6029d0: 0x000010db 0x000010eb 0x00001109 0x00001325 0x6029e0: 0x0000132d 0x00001341 0x00001352 0x00001370 0x6029f0: 0x00001380 0x00001750 0x00001760 0x000017ce 0x602a00: 0x00001c83 0x00001ca5 0x00001cb5 0x00001cc1 0x602a10: 0x00001d20 0x00001fcf 0x00001fea 0x00001fd9 0x602a20: 0x00002005 0x00002016 0x0000201a 0x00000179 0x602a30: 0x0000024b 0x00000a9f 0x0000177a 0x0000178e 0x602a40: 0x000017d5 0x00001b04 0x00001b3c 0x00001b85 0x602a50: 0x00001b99 0x00001bb1 0x00001c51 0x00001ca3 0x602a60: 0x00001d9d 0x00001dd0 0x00000ff1 0x00001003 0x602a70: 0x000010eb 0x000013ec 0x0000140f 0x00001420 0x602a80: 0x00001487 0x000014a2 0x000014ce 0x00001506 0x602a90: 0x0000002a 0x00000031 0x00000048 0x0000004f 0x602aa0: 0x000000aa 0x0000048b 0x00000498 0x000004af 0x602ab0: 0x000004b1 0x000004cd 0x000004d9 0x000004e5 0x602ac0: 0x0000054e 0x00001ed4 0x00001edb 0x00001ef5 0x602ad0: 0x00001ef6 0x00001f24 0x00001f39 0x00001f67 0x602ae0: 0x00001f97 0x00001fb6 0x00001fdf 0x000003aa 0x602af0: 0x000003cc 0x000003de 0x00000441 0x00000645 0x602b00: 0x00000859 0x0000097a 0x000009c1 0x00000a00 0x602b10: 0x00000a0a 0x00000a5c 0x00001d61 0x00001d92 0x602b20: 0x00001dd1 0x00001df5 0x00001e27 0x00001e4c 0x602b30: 0x00001e69 0x00001eef 0x0000015d 0x00000191 0x602b40: 0x000001b6 0x00000201 0x00000227 0x0000025b 0x602b50: 0x00000001 0x00000033 0x0000004f 0x00000114 0x602b60: 0x000001ad 0x00000210 0x00000261 0x000002e6 0x602b70: 0x0000033d 0x000003b7 0x000003d3 0x00001ef2 0x602b80: 0x00001f82 0x00001fb6 0x0000204a 0x00002075 0x602b90: 0x000020e2 0x0000211f 0x000021ae 0x00002268 0x602ba0: 0x00001afb 0x00001c0f 0x00001d80 0x000020c3 0x602bb0: 0x000021e0 0x0000223c 0x000023a3 0x00002491
So when this does print something...
It sleeps, then gets time and subtracts start time... so it effectively gets the sleep count back I think
That stops people just bypassing the sleep count
What is at BP-x18 ?
Can we just patch our way to that first bit
(gdb) b *0x401121 ; go up to sleep call - but not do it ; RAX has the 0x10cc ; So change that to 1 ; Grr never returns
OK need bp maybe, cos thread things
So...
(gdb) b*0x40113c (gdb) run (gdb) hb *0x401141 (gdb) set $rax = 1 (gdb) conti
OK weird... that also never returns.
Maybe just not do the sleep :)
Patch it out...
$ bvi \e83ff8ffff shift_R Patch to NOP = x90 * 5 00001130 FC 48 98 8B 04 85 C0 29 60 00 89 C7 90 90 90 90 .H.....)`....... 00001140 90 BF 00 00 00 00 E8 F5 F7 FF FF 89 C2 8B 45 F8 ..............E. ESC :wq
Rerun but bp at 0x401146
Gets there...
EDX has 6... (seconds elapsed time)
so patch that to 0x10cc
and follow on, until... just before strcpy() @0x401181
RSI: 0x4012a8 --> 0x3300373935393031 ('109597') # this is the 'extra bit' RDI: 0x7fffffffe260 --> 0x7ffff7bc71e0 (<__wait_lookup_done>: push r14) ; Ah OK maybe this is output bufferage... building huge number ? ; Now strcat() on the time bit 0x10cc => 4300 decimal, @ 0x401197 RSI: 0x7fffffffe2d0 --> 0x30303334 ('4300') RDI: 0x7fffffffe260 --> 0x373935393031 ('109597') ; Giving: RDI: 0x7fffffffe260 ("1095974300")
Table lookup via RAX*4 + 0x602300 gives these :
(gdb) x/100xw 0x602300 0x602300: 0x0000012c 0x00000014 0x00000017 0x00000009 0x602310: 0x00000014 0x0000000d 0x0000000f 0x0000001e 0x602320: 0x0000000e 0x00000003 0x00000002 0x0000000a 0x602330: 0x00000006 0x0000000c 0x00000009 0x00000021 0x602340: 0x00000005 0x00000014 0x0000000a 0x00000003 0x602350: 0x0000000d 0x00000002 0x00000007 0x00000010 0x602360: 0x0000012c 0x0000000d 0x00000002 0x00000016 0x602370: 0x0000000d 0x00000012 0x0000000a 0x00000004 0x602380: 0x0000000c 0x00000063 0x00000006 0x0000000b 0x602390: 0x00000014 0x00000013 0x00000020 0x0000000b 0x6023a0: 0x00000009 0x0000000a 0x0000000f 0x0000000b 0x6023b0: 0x00000002 0x00000013 0x00000011 0x00000004 0x6023c0: 0x00000032 0x0000000c 0x0000000a 0x00000003 0x6023d0: 0x00000016 0x00000001 0x0000000c 0x0000000f 0x6023e0: 0x0000000b 0x00000013 0x0000000b 0x0000000c 0x6023f0: 0x00000002 0x0000000a 0x00000028 0x00000019 0x602400: 0x00000008 0x0000000b 0x0000000c 0x00000003 0x602410: 0x00000004 0x0000000c 0x00000013 0x00000006 0x602420: 0x0000000d 0x00000014 0x0000001f 0x00000009 0x602430: 0x00000010 0x00000001 0x00000003 0x00000007 0x602440: 0x0000000b 0x00000004 0x00000003 0x00000013 0x602450: 0x0000000b 0x00000021 0x0000000a 0x0000001e 0x602460: 0x00000009 0x00000003 0x00000024 0x0000003c 0x602470: 0x00000033 0x0000000b 0x00000014 0x0000000c 0x602480: 0x000000c8 0x00000002 0x00000001 0x00000009
to RCX
So in this case first entry 0x12c
RDX gets pointer to a function or table
RDX: 0x7fffffffe334 --> 0x4012a800000000
Hmmm
(gdb) x/256bx 0x4012a8 0x4012a8: 0x31 0x30 0x39 0x35 0x39 0x37 0x00 0x33 0x4012b0: 0x30 0x30 0x30 0x00 0x33 0x30 0x30 0x00 0x4012b8: 0x38 0x30 0x38 0x00 0x33 0x36 0x39 0x00 0x4012c0: 0x31 0x36 0x34 0x37 0x36 0x30 0x30 0x30 0x4012c8: 0x00 0x31 0x36 0x34 0x37 0x36 0x30 0x30 0x4012d0: 0x00 0x31 0x36 0x34 0x37 0x36 0x30 0x00 0x4012d8: 0x36 0x34 0x34 0x00 0x36 0x35 0x30 0x30 0x4012e0: 0x00 0x36 0x35 0x30 0x00 0x36 0x36 0x39 0x4012e8: 0x00 0x36 0x33 0x37 0x30 0x00 0x38 0x39 0x4012f0: 0x32 0x35 0x36 0x30 0x30 0x30 0x00 0x38 0x4012f8: 0x39 0x32 0x35 0x36 0x30 0x30 0x00 0x38 0x401300: 0x39 0x32 0x35 0x36 0x30 0x00 0x33 0x31 0x401308: 0x35 0x00 0x31 0x00 0x00 0x00 0x25 0x78 0x401310: 0x00 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x401318: 0x37 0x38 0x39 0x61 0x62 0x63 0x64 0x65 0x401320: 0x66 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x401328: 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x401330: 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x401338: 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x23 0x401340: 0x23 0x23 0x23 0x23 0x23 0x23 0x00 0x1b 0x401348: 0x5b 0x39 0x41 0x00 0x00 0x00 0x00 0x00 0x401350: 0x74 0x68 0x69 0x73 0x20 0x6d 0x61 0x79 0x401358: 0x20 0x74 0x61 0x6b 0x65 0x20 0x74 0x6f 0x401360: 0x6f 0x20 0x6c 0x6f 0x6e 0x67 0x20 0x74 0x401368: 0x69 0x6d 0x65 0x20 0x2e 0x2e 0x2e 0x20 0x401370: 0x3a 0x29 0x00 0x00 0x00 0x00 0x00 0x00 0x401378: 0x45 0x72 0x72 0x6f 0x72 0x20 0x2d 0x20 0x401380: 0x70 0x74 0x68 0x72 0x65 0x61 0x64 0x5f 0x401388: 0x63 0x72 0x65 0x61 0x74 0x65 0x28 0x29 0x401390: 0x20 0x72 0x65 0x74 0x75 0x72 0x6e 0x20 0x401398: 0x63 0x6f 0x64 0x65 0x3a 0x20 0x25 0x64 0x4013a0: 0x0a 0x00 0x25 0x64 0x00 0x00 0x00 0x00
RAX gets pointer to
RAX: 0x7fffffffe260 ("1095974300")
ESI gets the table pointer from ECX
RDI gets the one from EAX
OK so just want to see what comes out from the loopy/crazy/complicated routines... called via 0x400d65
so
(gdb) hb *0x4011b8 conti
OK just going to patch it to bypass the time/sleep checks passing correct value through and see what happens...
We NOP out a block
401133: 8b 04 85 c0 29 60 00 mov 0x6029c0(,%rax,4),%eax NOP all this ---> 40113a: 89 c7 mov %eax,%edi # sleep something edi... 40113c: e8 3f f8 ff ff callq 400980# sleep () !!!! not usleep... LOOONG sleep()s 401141: bf 00 00 00 00 mov $0x0,%edi 401146: e8 f5 f7 ff ff callq 400940
Leaving the top and bottom instructions there...^^^ this gets the sleep() time value and pretends we slept that long
... probably (TM) ...
Now we have
00001110 00 00 00 00 48 89 C7 E8 C4 F7 FF FF E9 CA 00 00 ....H........... 00001120 00 BF 00 00 00 00 E8 15 F8 FF FF 89 45 F8 8B 45 ............E..E 00001130 FC 48 98 8B 04 85 C0 29 60 00 90 90 90 90 90 90 .H.....)`....... ;00001160 13 40 00 48 89 C7 B8 00 00 00 00 E8 00 F8 FF FF .@.H............
Run it
$ ./leach
Yay !!!
ASIS{--redacted--}