Rating:

<span>Secure Shell Server
<span>
This challenge involves getting arbitrary shell access to a secure shell server
</span>
Welcome to Secure Signed Shell

1) sign command
2) execute command

>_</span><span>
As always, we can start by fuzzing all the string input states of the program, we quickly find that entering more than 256 characters into the execute command prompt causes seg faults indicating a possible buffer overflow, invalid instructions, or memory corruption.</span><span>We can look at the area in memory where the command is stored, and we find it to be a global section obj.global of size 0x100 (256). In running the code, however, we notice that the null byte termination at the end of the string overwrites a value directly after the global section, specifically the byte at address 0x00602240. This byte is then used to determine whether to run a SHA1 or MD5 hashing of the command. We know it does MD5 by default due to the length of the signatures of whitelisted commands (ls, whoami, ...). We don't yet know why the segfault appears, but we do notice we can change execution by altering which path je 0x4011f2 takes
</span> 
0x401145 ;[ge]
mov edi, str.what_command_do_you_want_to_run_
call sym.imp.puts ;[gg]
mov edi, 0x401622
mov eax, 0
call sym.imp.printf ;[gh]
mov edx, 0x100
mov esi, obj.global
mov edi, 0
call sym.imp.read ;[gi]
mov dword [rbp - local_54h], eax
mov eax, dword [rbp - local_54h]
cdqe
mov byte [rax + obj.global], 0
mov qword [rbp - local_40h], obj.global
movzx eax, byte [0x00602240]
test al, al
je 0x4011f2 ;[gj]
<span>
We can continue execution to determine what call causes the segfaults and we find a register call to an address stored at obj.m_exec_guy + 0x13. Depending on the overflow input the call to rax gives different results.</span>


0x401369 ;[gAd]
mov rax, qword [obj.m_exec_guy]
mov rax, qword [rax + 0x13]
mov edi, obj.global
call rax
jmp 0x40138f ;[gAc]
<span>
Let's quickly examine the setup for this memory location, it appears to create an obj.s_exec_guy and obj.m_exec_guy, finding usage of these pointers suggests they are for storing the SHA1 and MD5 hashes (hence s and m prefixes). Since the hashes are different lengths it makes sense obj.s_exec_guy provides more space than obj.m_exec_guy. However the address to the functions to deny_command and exec_command lie directly after the stored hash.</span>


0x4010c8 ;[gd]
mov esi, 1
mov edi, 0x24
call sym.imp.calloc ;[gc]
mov qword [obj.exec_guy], rax
mov rax, qword [obj.exec_guy]
mov qword [obj.s_exec_guy], rax
mov rax, qword [obj.exec_guy]
add rax, 1
mov qword [obj.m_exec_guy], rax
mov rax, qword [obj.s_exec_guy]
mov qword [rax + 0x14], sym.deny_command
mov rax, qword [obj.s_exec_guy]
mov qword [rax + 0x1c], sym.exec_command
<span>
Now the exploit becomes clear, by controlling the SHA1/MD5 jump we can effectively choose the length of the hash stored at the address determined at the beginning of execution. Since the program expects to perform MD5, if we change the execution to be SHA1 it will store a larger hash than expected in the obj.m_exec_guy location, thus overwriting the last (endianness) two bytes of the address sym.deny_command. Luckily the addresses for sym.deny_command and sym.exec_command differ by only two bytes, thus by hashing enough different inputs we can overwrite the deny address to jump to the exec address. Then so long as our input command is at least partially valid in shell we can execute the command and return the result.
</span><span>
See website for code

output: trying: cat flag;DEXotxgPoDkrkHpgaVubVrFGOvTOPWgreLTocJHJmZGpLeLgChPKeLCjLYDFacUyxXVcdrUqmdRPVLIAwtgKjJsRPKlmhRTCTOamDyaqTFQfRFtfNWEbpcMIfupVOzMkejNAXYhWujNGWAbMVOGfUdotGMjFOfhzLKjzoKTQXEFTCtwBqfndBvDmdWIpJOXauQitisLLouNDksWcOcISPqPenZSdsfoOHvglTqWIEjCvAbIyqpRjWHw ANSWER: bkp{and you did not even have to break sha1}
</span>

Original writeup (https://chc.cs.cornell.edu/writeups/6/).