Our CTF in Kraków ended today - big "Thanks!" goes to each and every team and player that participated, we hope you had fun :). After 27 hours of playing and quite a lot of shuffling going up all around the scoreboard, the winners were decided:
1. MSLC
2. H4x0rPsch0rr
3. SpamAndHex
Congratulations!
We'll probably write another post about the CTF/tasks/etc later on (after everyone gets enough sleep - currently some of our team members had forgotten what "sleep" is), however due to popular demand we wanted to publish the slides of our post-CTF presentation during which we explained the key points of all tasks we published during the CONFidence 2015 CTF:
Link: Tasks Explained
(It's a Google Slides presentation. To download in PDF please click File → Download → PDF.)
Please also find a quick photo of the final first page of the scoreboard below. And with that we'll end this post for now - good night!
Tuesday, May 26, 2015
Thursday, April 23, 2015
The CONFidence Teaser CTF takes place this weekend!
The registration has just started at the event's website, https://ctf.dragonsector.pl/, and will stay open all throughout the game.
A quick rundown on the basic information is as follows:
- Start: 25 April 2015, 10:00 CEST
- End: 26 April 2015, 10:00 CEST
- Duration: 24h
- Format: online, jeopardy, team-based, no team size limit, teaser
- Categories: web, re, pwn, crypto, stegano
- Contact (IRC): #dragonsector @ irc.freenode.org
- Contact (e-mail): ctf@dragonsector.pl
Prizes:
Top 1:- Travel allowance if coming to the offline event (up to 4*500 USD for European teams and 4*1500 USD for non-European teams)
- 4 conference passes for CONFidence
- 4 places in a rent-out hostel for conference attendees
- 4 conference passes for CONFidence
- 4 places in a rent-out hostel for conference attendees
See you on the battlefield!
Monday, March 2, 2015
Boston Key Party 2014 / Riverside
Get the file :
# wget http://bostonkeyparty.net/challenge.pcapng.28c58da9dd07532d45aa68f9b825941e
# file challenge.pcapng.28c58da9dd07532d45aa68f9b825941e challenge.pcapng.28c58da9dd07532d45aa68f9b825941e: pcap-ng capture file - version 1.0
Lot of USB data inside:
# tshark -r challenge.pcapng.28c58da9dd07532d45aa68f9b825941e | head
1 0.000000000 host -> 1.0 64 USBHUB GET_STATUS Request
2 0.000011000 1.0 -> host 68 USBHUB GET_STATUS Response
3 0.074167000 host -> 12.0 64 USB GET DESCRIPTOR Request DEVICE
4 0.075077000 12.0 -> host 82 USB GET DESCRIPTOR Response DEVICE
5 0.150556000 host -> 1.0 64 USBHUB GET_STATUS Request
6 0.000015000 host -> 1.0 64 USBHUB GET_STATUS Request
Device [12.0] description:
DEVICE DESCRIPTOR
bLength: 18
bDescriptorType: DEVICE (1)
bcdUSB: 0x0200
bDeviceClass: Use class info in Interface Descriptor (0x00)
bDeviceSubClass: 0
bDeviceProtocol: 0
bMaxPacketSize0: 8
idVendor: 0x046d <---- Logitech Inc.
idProduct: 0xc00e <---- Logitech Optical Mouse,
bcdDevice: 0x1100
iManufacturer: 1
iProduct: 2
iSerialNumber: 0
bNumConfigurations: 1
( Ref: http://www.pcidatabase.com/vendor_details.php?id=1691)
Take sample data:
# tshark -r challenge.pcapng.28c58da9dd07532d45aa68f9b825941e 'usb.device_address == 12' -x
....
105 5.078857000 12.1 -> host 68 USB URB_INTERRUPT in
0000 c0 44 a9 c7 00 88 ff ff 43 01 81 0c 02 00 2d 00 .D......C.....-.
0010 7f 99 ea 54 00 00 00 00 93 3c 09 00 00 00 00 00 ...T.....<......
0020 04 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
0030 08 00 00 00 00 00 00 00 04 02 00 00 00 00 00 00 ................
0040 00 01 00 00
....
Find tech spec:
struct mouse_report_t
{
uint8_t buttons;
int8_t x;
int8_t y;
int8_t wheel;
}
Write parser -> och it is on-screen keyboard:)
Enhance parser :
Monday, January 19, 2015
31C3 CTF - Mynx (Pwn 30)
After selecting this challenge we were welcomed by a rather laconic description:
Once connected to the service, we were greeted by the following menu:
Menu |
It appeared to be some kind of a storage service for ASCII art. We could upload ASCII arts, add comments and apply filters. After fuzzing the input for a while we didn’t discover anything useful, so it was time to look inside the executable.
Reversing the binary
The file command
revealed that it was an x86 ELF executable. After opening it in IDA we
could see a main loop which was responsible for displaying the
minimalistic menu shown in the previous picture. Its C representation looks something like that:
Because vulnerabilities are often caused by badly handled user input it is a good idea to look for some potential overflows. There are 3 places where input from user is requested:
Main function |
Because vulnerabilities are often caused by badly handled user input it is a good idea to look for some potential overflows. There are 3 places where input from user is requested:
- the read_3_digits function
- the add_art function
- the add_comment function
When adding a new structure, the program looked for the first free slot and placed the structure there. We reconstructed the “art” and “comment” structures, which were both 256 bytes long:
Vulnerability
These structures were filled when a new ASCII art or a comment was added. The interesting fact was that, when a comment was added, 252 bytes of input were read into a buffer of size 251, so there was an overflow after all!
It was just a single byte, but that was all we needed. Using this one byte we could overwrite the first byte of the next structure which was a type field. So we could convert a comment object into an art object and vice versa. The first one was particularly useful because when a comment was interpreted as an ascii_art then the first 4 bytes of the comment string were interpreted as a function pointer named “filter_method”. By applying a filter we would be executing arbitrary address with our string as first argument. In other words, we could simply call system() and get a remote shell. :)
All we needed was to overwrite a comment and change it to art.
After that there would be two ascii_art structures with the same id
(ascii art and its comment converted to ascii_art). We needed our
transformed comment to be earlier in memory so that it was selected
first. We achieved this by making use of the remove_comments function. This step could have been done in many different ways but we discovered the following first:
- Add two ascii_arts A1 and A2.
- Add two comments C1 and C2 (Cx is a comment for Ax).
- Add ascii_art A3.
- Remove comment C2 and add comment C3 (it will be put in C2’s place).
- Remove comment C1 and add comment C2 (it will be put in C1’s place).
With
the last one we overwrited C3’s type field and turned it into an ascii
art. It was placed before the original A3 and thus when ascii art with
id=3 was requested our spoofed art was selected. Applying a filter
resulted in arbitrary address call with the argument being an address of
a controlled string.
Exploitation
Because ASLR as well as NX were enabled (no PIE/RELOC though), we needed a memory leak in order to call the system function (or we could have created a ROP but come on - we had function call with our string as argument).
Fortunately for us, there was a printf
function imported by the executable, so we could force a format string
vulnerability by simply calling it with a controlled string. Sadly, our
format string was not stored on the stack, so leaking .got entries
became much, much harder than it typically is.
Cheer up, not everything was lost. The “main” function is not called directly at program startup but through the __libc_start_main function which is a part of libc, so the return address from the main function also resides in libc. And this one is definitely on the stack.
After
finding the correct offset and leaking the address, all we needed to do
in order to get the flag was to find out what version of libc the
system was using (so we could calculate the distance between the leaked
return address and the system
function).
In the end, we failed to identify the specific libc build
and consequently had to brute force the offset remotely. It took
approximately 8 hours, but we eventually got the system address right and obtained the flag.
Conclusions
To exploit this challenge we used function pointer overwrite, combined with custom memory management, and then forced format string vulnerability by calling printf function. Knowing libc base address we called system() and spawned remote shell.
It was a great CTF challenge and I personally enjoyed how the solution leveraged one vulnerability to cause another. I thank the organizers for interesting contest and I hope it will be even better next year.
Subscribe to:
Posts (Atom)