TGTGInsighttelegram intelligenceLIVE / telegram public index
← Welcome to the Black Parade
Welcome to the Black Parade avatar

TGINSIGHT POST

Post #436

@TheB1ackParade

Welcome to the Black Parade

Views243Post view count
PostedNov 411/04/2023, 09:50 AM
Post content

Post content

ustc-hackergame2023 又结束了,每次 zzh 和馒头都盛情邀请但我却只在最后一天看了一道题。。。 Komm, süsser Flagge 的第三小题其实比想象中细节更多。很容易想到是加 ipv4 option,但是怎么加,加什么内容,简直是和内核贴身肉搏。 我一开始直接加 'GET / HTTP',果然被内核扔了,pwru 能看到 kfree_skb_reason(SKB_DROP_REASON_NOT_SPECIFIED)。写一段 bpftrace 检查真·调用栈: bpftrace -e 'k:kfree_skb_reason {$skb=(struct sk_buff*)reg("di"); $data=$skb->network_header+$skb->head; if (*(uint8[4]*)((uint8*)$data+16)==pton("1.1.1.1")) {printf("%s %s\n", ksym(*(uint64*)reg("sp"), kstack)} } ' 看到是结果是 ip_rcv -> ip_rcv_finish_core 里扔掉的。看代码,搜 goto drop,定位 if (iph->ihl > 5 && ip_rcv_options(skb, dev)) goto drop; 继续检查,发现 ip_options_compile 返回非零。开始让 gpt 帮我构造一个合法 ip option。是的你们看 wiki 就知道要构造合法 option 我非要撞墙弹回来才落泪。 终于发现用 0x44 + len 可以塞任意字符串,然后遇到题解里所说的 GET 变成 GUT 的问题。这我就轻车熟路了,用 skbdump 在内核抓几个包: skbdump -i any -k tcf_classify,__ip_options_compile 'dst host 1.1.1.1 and tcp[tcpflags] = tcp-syn' 再用 wireshark 肉眼检查,确实是 __ip_options_compile 修改的。 检查代码,搜索 [3] 直接定位 } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) { unsigned int overflow = optptr[3]>>4; if (overflow == 15) { pp_ptr = optptr + 3; goto error; } if (skb) { optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4); opt->is_changed = 1; } 修改逻辑是 >>> def change(c): return chr((ord(c) & 0xf) | (((ord(c)>>4)+1)<<4)) >>> change('E') 'U' 所以可以找一个字节,其修改后的字节是 E: >>> for i in range(100): ... if change(chr(i)) == 'E': print(i) ... 53 但是这又不满足修改的条件 `if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC)`。所以还是像题解一样做就好。 内核因为提供 API 设置 ip option,所以题解应该是最速解法。我用 bpf 做这个属于蚊子轰大炮了。要点有两个: 1. 不能用 bpf_skb_change_head。这个 helper 改变的是 skb->mac_header 但是不改 skb->network_header。应该用 bpf_skb_adjust_room 在 L3 和 L4 之间加空。 2. 别忘了 bpf_l3_csum_replace 修改三层校验和。(tc bpf 修改校验和真愉快,隔壁 xdp bpf 还要手动 fold 真是有种中世纪的美) 赶紧打游戏。。。