CSAW CTF 2014 - Saturn - Pwn400 - Writeup

Hello,

The task was about bypassing a challenge response authentication system, without having access to the library that check the submittet response. The first run of the binary gives a message telling that the libchallengeresponse.so is missing.

./saturn: error while loading shared libraries: libchallengeresponse.so: cannot open shared object file: No such file or directory

So, I managed to create the missed library and functions. I imported the binary into IDA and i got a loook at the Imports list. fillChallengeResponse() is an extern function loaded from the libchallengeresponse.so shared library. Its not the goal to know what this function do. But we have to write a dumb one and compile it into the missed shared lib. But what is the signature of the function ? Lets get a look at the function call :

.text:08048A84                 mov     edx, off_804A054
.text:08048A8A                 mov     eax, off_804A050
.text:08048A8F                 mov     [esp+4], edx
.text:08048A93                 mov     [esp], eax
.text:08048A96                 call    _fillChallengeResponse
.text:08048A9B                 cmp     eax, 0FFFFFFFFh
.text:08048A9E                 jnz     short loc_8048AAC
.text:08048AA0                 mov     dword ptr [esp], 1 ; status

The fillChallengeResponse function take two (char*) arguments and return an int status. Lets write it :

int fillChallengeResponse(char *a, char *b)
{
a[0] = 'A';
a[1] = 'B';
a[2] = 'C';
a[3] = 'D';
b[0] = '1';
b[1] = '2';
b[2] = '3';
b[3] = '4';
printf("fillChallengeResponse lib calledn");
return  0;
}

Then compile the shared lib.

gcc -c -Wall -Werror -fpic libchallengeresponse.c
gcc -shared -o libchallengeresponse.so libchallengeresponse.o
cp libchallengeresponse.so /usr/lib/
ldconfig

Now running the binary gives : fillChallengeResponse lib called CSAW ChallengeResponseAuthenticationProtocol Flag Storage It works fine. Lets analyze the binary. One interresting function is the sub_8048A01 function that will read the flag.txt file and print out the flag. But before that this function call another function sub_80487ED to check whether to print the flag or not. So the goal now is to set the ds:dword_804A0A0 var to 1. But how ? simply by giving the correct challenge response the the service.

The sub_8048825 reads 1byte from the stdin and then 4 cases are possible. If the char was 0xA0 -> the binary prints out the challenge. If the char was 0xE0 -> the binary will read 4 chars from the stdin buffer and will check if the challenge response is correct(as described below). If the char was 0x80-> the binary will check if the entred challenge response is correct and decide wether printing the flag or not. Any Other char -> The program will exist. Now lets look closer the the sub_8048825 function. It take as argument the entred char and apply the following operation to it.

.text:0804886D                 and     eax, 0Fh
.text:08048870                 mov     [ebp+var_11], al
.text:08048873                 mov     eax, off_804A050
.text:08048878                 movzx   edx, [ebp+var_11]
.text:0804887C                 shl     edx, 2
.text:0804887F                 add     eax, edx
.text:08048881                 mov     eax, [eax]

Now imagine that we entred the 0xA1 byte. (0xA1 & 0x0F) « 2 gives 4 The function in this case will print 4 chars from the off_804A050+4 buffer. Have we some interrsting buffer arround off_804A050 ? Yes we have the off_804A054 pointer that holds the challenge response. Now we can exploit the sub_8048825 function to read its content. off_804A050 is a pointer the unk_804A0C0 var which is a 32 bytes array. off_804A054 is a pointer to unk_804A0E0 var which is a 32 bytes array. unk_804A0C0 and unk_804A0E0 are contiguous blocks.Now to read the challenge response value. (32 » 2) OR 0xaf = 0xA8 Putting it all together. 1) We send one byte “xa8” to the server. 2) The server sends us the challenge response(imagine that we got 4 bytes ABCD) 3) We send tback o the server 5 bytes “xe0ABCD” 4) The server cheks the challenge response which is correct and set ds:dword_804A0A0 to 1 5) We send one byte “x80” 6) The server attempts to test about ds:dword_804A0A0 and the flag is sent. Now just redo this scenario 8 times to get the flag. The flag was :

The flag was : flag{greetings_to_pure_digital}

Written on December 2, 2014