Okay so a few days back I got bored and decided to try my hand at some of Defcon’s 2008 CTF binaries.
For those not familiar with Defcon CTF, it’s basically a contest that consists of seven teams of highly skilled individuals. Each team must defend their server and attack the other teams server. For a more in depth description I’ll refer you to this page:
Now before you go on reading this article… I want to point out that I was unable to get this binary to function correctly(or at all for that matter) on my FreeBsd 6.4 VM… So the write up I’m presenting here is mainly the outcome of my time spent performing static analysis and thus it may be incorrect. I’m hoping that if I am incorrect in my solution that someone may be able to correct me.
Well, of course we start by downloading the binary in question, you can find it here:
Thanks go out to 1@stPlace for uploading the binaries :), If you guys are reading this, I’d really like to hear from you.
We start by checking the file type:
[KOrUPt@Area51 /usr/home/KOrUPt/defcon]$ file catdoord
catdoord: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD),
dynamically linked (uses shared libs), stripped
No debug symbols, this makes disassembling with GDB rather awkward. But it isn’t a problem in this case as I’m using IDA.
I’ll be focusing on explaining the main callback procedure of this binary as the initial routines are near enough the same throughout every other available service. Just to outline the basic functionality:
- Listen for connections on port 4341.
- Drop “catdoor”’s user privileges.
- Accept incoming connections and enter the client callback routine.
The callback routine in question can be found at the following address:
Upon starting my initial analysis of the callback routine I used HexRays IDA decompiler plugin. This helped simplify a fair amount of the code.
I could see a few uninitialized variable’s being passed to memcpy:
pSzChar = &szChar;
pStruct = &struct[i++]; // 'i' is globally defined
memcpy(pStruct, &szChar, 8u);
the unknown structure is defined as follows:
.bss:0804A7C0 struct struct_0 200h dup()
Regarding the calls to memcpy(), we see similar code throughout or analysis, this kept me wondering for quite a while but eventually I came to the conclusion that it must be a red-herring of sorts. I’ll go into more detail shortly.
Continuing our analysis we see a few calls to unknown functions, after a little time analysing them, it’s clear that the first seems to be a wrapper for the recv() function.
Its code is as follows and as you can see I’ve named this function “RecvData”:
; int __cdecl RecvData(SOCKET sock, char *buf)
.text:08049338 RecvData proc near ; CODE XREF: callback+70
.text:08049338 fd = dword ptr -8
.text:08049338 nbytesRecvd = dword ptr -4
.text:08049338 sock = dword ptr 8
.text:08049338 buf = dword ptr 0Ch
.text:08049338 push ebp
.text:08049339 mov ebp, esp
.text:0804933B sub esp, 8
.text:0804933E mov [ebp+nbytesRecvd], 0
.text:08049345 mov edx, [ebp+fd]
.text:08049348 lea edx, [esp+8] ; first function parameter
.text:0804934C mov eax, edx
.text:0804934E mov [ebp+fd], eax
.text:08049351 sub esp, 4
.text:08049354 push 8 ; size_t
.text:08049356 push [ebp+fd] ; void *
.text:08049359 mov eax, ds:i
.text:0804935E shl eax, 3 ; counter << 3
.text:08049361 add eax, offset struct
.text:08049366 push eax ; void *
.text:08049367 inc ds:i
.text:0804936D call _memcpy
.text:08049372 add esp, 10h
.text:08049375 recvLoop: ; CODE XREF: RecvData+5C
.text:08049375 push 0 ; flags
.text:08049377 push 4096 ; len
.text:0804937C push [ebp+buf] ; buf
.text:0804937F push [ebp+sock] ; s
.text:08049382 call _recv
.text:08049387 add esp, 10h
.text:0804938A mov [ebp+nbytesRecvd], eax
.text:0804938D cmp [ebp+nbytesRecvd], 4095
.text:08049394 jg short recvLoop
.text:08049396 sub esp, 4
.text:08049399 push 8 ; size_t
.text:0804939B dec ds:i
.text:080493A1 mov eax, ds:i
.text:080493A6 shl eax, 3
.text:080493A9 add eax, offset struct
.text:080493AE push eax ; void *
.text:080493AF push [ebp+fd] ; void *
.text:080493B2 call _memcpy
.text:080493B7 add esp, 10h
.text:080493BA mov eax, [ebp+nbytesRecvd]
Again, we see more operations taking place in regard to these mysterious structures. After going over the disassembly it’s worth noting that the data we send to this service does not appear to effect any variable’s used in the operations involving the unknown structure’s. Given we are trying to exploit the service I cannot see how the use of these structures may present a vulnerability and it is for this reason I decided to divert my attention to the other parts of the code.
Whilst writing this a quick thought has come to mind, unfortunately I’m unable to put this theory to the test at the moment, but perhaps an overflow condition is created during the receiving of data over the socket, which in turn overwrites the address of the functions local variable’s and the hardship is that of trying to keep the service up and running? This would address my later concern(which I’ll mention shortly). Any comments?
Disregarding my above sentiments, I shall continue with my explanation.
Just after the call to RecvData(), we’ve a second function being called, this one I’ve decided to call “WriteData”. Its code is as follows:
size_t __cdecl WriteData(int a1, void *buff, size_t length)
void *pStruct; // ST00_4@1
char *envHome; // eax@1
FILE *pFile; // eax@1
size_t bytesWritten; // eax@3
size_t pBytesWritten; // [sp+41Ch] [bp-Ch]@1
char filename; // [sp+10h] [bp-418h]@1
FILE *pFile2; // [sp+Ch] [bp-41Ch]@1
void *localStruct; // [sp+8h] [bp-420h]@1
pBytesWritten = 0;
memset(&filename, 0, 1024u);
pFile2 = 0;
localStruct = &localStruct;
pStruct = &struct[i++];
memcpy(pStruct, &localStruct, 8u);
envHome = getenv("HOME");
snprintf(&filename, 1024, "%s/.ssh/authorized_keys2", envHome);
pFile = fopen(&filename, "w+");
pFile2 = pFile;
if ( pFile )
bytesWritten = fwrite(buff, 1u, length, pFile2);
pBytesWritten = bytesWritten;
if ( (signed int)bytesWritten >= 0 )
memcpy(localStruct, &struct[i], 8u);
Again we see more operations involving our structures. But more importantly we can see that this code is overwriting the “~/.ssh/authorized_keys2″ file with the data we received over our socket earlier.
In theory, we should be able to generate a pair of DSA keys(public and private), overwrite the authorized_keys2 file with our public key and login via SSH using our chosen passphrase.
To further your understanding of this concept, I’ll quote a web page I read prior to writing this:
DSA key generation
While RSA keys are used by version 1 of the ssh protocol, DSA keys are used for protocol level 2, an updated version of the ssh protocol. Any modern version of OpenSSH should be able to use both RSA and DSA keys. Generating DSA keys using OpenSSH’s ssh-keygen can be done similarly to RSA in the following manner:
“% ssh-keygen -t dsa”
Again, we’ll be prompted for a passphrase. Enter a secure one. We’ll also be prompted for a location to save our DSA keys. The default, normally ~/.ssh/id_dsa and ~/.ssh/id_dsa.pub, should be fine. After our one-time DSA key generation is complete, it’s time to install our DSA public key to remote systems.
DSA public key install
Again, DSA public key installation is almost identical to RSA. For DSA, we’ll want to copy our ~/.ssh/id_dsa.pub file to remotebox, and then append it to the ~/.ssh/authorized_keys2 on remotebox. Note that this file has a different name than the RSA authorized_keys file. Once configured, we should be able to log in to remotebox by typing in our DSA private key passphrase rather than typing in our actual remotebox password.
Once we’ve SSH access there are many things that can be done. As I’m sure you’re aware of. On that note, we have effectively gained a means towards unauthorized access to the target machine(this being a game, we’re not breaking any laws :p).
Now to address my earlier concern… This is too easy! From my past experiences most Defcon services are rather complex, this service just doesn’t seem to be on the same level as the past ones I’ve faced. Thus for some reason I cant help but think I’m wrong in this explanation…
Well, given my current time constraints I’ll wrap this up here.
Please do not hesitate to leave me a comment and as always I hope you liked the read.
I’ll be having a go at some of the other Defcon binaries soon so stay tuned for more writeups :).