最近学的知识有点杂,这次还是围绕两道web题,稍微记录点东西
两道题是 fakebook还有Cat
知识点概要
fakebook
简单概述一下,用到的知识点
sql注入
绕过
union select
爆表名、字段名、数据库名、各个字段的内容
php curl
curl 的 file:// 协议用法
php反序列化
html中 iframe
iframe 的 src 有两种,一是url,二是Data URI
御剑扫描
Cat
简单概述一下用到的知识点
gbk编码问题
gbk编码,如果第一个字节大于等于0x80那么这个字节和它后面的一个字节将被看做同一个字符的编码
php curl POST上传文件
能用在url中的,就是
@+文件名
数据库文件格式
这题中用到 sqlite3为后缀得到文件存储数据库数据
具体wp
fakebook
拿到手,先玩一玩,注册,登录……
然后发现在view.php
有个注入点,那就注入试试看
order by 4
没问题
order by 5
报错
一开始看,拦截 了 select
,但是实际上,是拦截了 union select
这个整体
union select
可以用 union++select
或者union/**/select
来绕过
爆出数据库名 :fakebook
爆出表名:users
爆出所有字段:
group_concat(column_name),3,4 from information_schema.columns where table_name='users'
dirsearch一下
看看robots.txt
看看user.php.bak
有一个get方法,里面直接curl了$this->blog
想到也许可以ssrf,即用file协议读服务器上的文件
随便join看看
报错了
这里有个方法,估计就是用来判断blog是否满足正则
分析一波
blog不能以file://开头了,那就得另想办法
随便注册一个
点开看看
看看the contents of his/her blog
发现有个iframe
好奇如果blog是www.baidu.com会怎么样
即使是正常的url也没怎么样
再看看,发现这个src有点奇怪
查了一下,src=后的参数,可以有两种,一是 url ,二是DATA URI
Data URI的格式这样:
src="data:<MIME Type>;base64,<content>"
做个试验,写个js代码到iframe里面看看
现在就打开浏览器,访问str.php,预期是看到弹窗
果然可以
如果我写入一个图片行吗
试了试看,确实行
那么就看懂了,这个iframe用的是Data URI,打印出来的内容用base64编码解码后,直接写在HTML中
但是正如图片中看到的,当base64,
后面是空的的时候,什么也没有。
再注一下,确定一波信息
发现几个要点
- php unserialize
- 回显的位置是2
- view.php所在位置是
/var/www/html/
再看一眼所有字段
no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS
看看每个字段有没有什么异端
看看no字段
看看username字段
看看passwd字段
密码看来是md5过的
看看data字段
发现有点东西——两个对象的序列化,和user.php对比,可以发现
序列对应的对象,正好是这个UserInfo
的实例
因此推测,unserialize
的内容就可能取自这里,即data
字段
看看USER字段
报错了
剩下两个也都报错
在页面下方,仔细看看,在contents of his/her blog
部分,还有一个报错
可以猜测,每次select
,先从data
中取一个序列,序列生成一个对象,对象调用了getBlogContents()
方法,然后成为了contents的内容
正常情况下,no
如果是存在的,那么一个no
就对应了一个data
,一个username
,一个age
,unserialize
的内容,猜测取自data
,所以data
大概率是在1或者3或者4的位置被select
了
复制过来试试看,看看底下有没有报错,就能确定哪个是data
'O:8:"UserInfo":3:{s:4:"name";s:5:"hello";s:3:"age";i:0;s:4:"blog";s:7:"a.a.abc";}'
3的位置报错
试试4的位置
对了,就是4的位置,select
了data
现在,就要借助getBlogContents
函数,来读取服务器中的文件了
用到file协议
:file:///var/www/html/index.php
'O:8:"UserInfo":3:{s:4:"name";s:5:"hello";s:3:"age";i:0;s:4:"blog";s:30:"file:///var/www/html/index.php";}'
看看index.php
看看db.php
好像也没什么用
flag到底在哪里呢?
使用御剑
,用php的字典来扫
谁也没有想到,竟然有一个flag.php
文件,所以直接读
http://220.249.52.134:40925/view.php?no=0 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"hello";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'#
Cat
看到题目,猜测是用到ping了,输入个127.0.0.1
,确实ping 通了
而且看到是php
开发的
再试试看,发现www.baidu.com
不能ping通,但是对应的ip 可以
再继续尝试输入各种字符,初步猜测,url参数中只能有 [a-z0-9A-Z/.-],否则就报错URL Invalid
试试看,这个网站处理宽字节会有什么问题吗
%80
取得了重大进展,报错了
复制下来,放到一个html中,好好看看报错的信息
其中有一些要点
分析一波:
在view.py中看到ping
函数,接收的是POST,可见当前页面是把url
当做post的数据再传到127.0.0.1/api/ping
中,且post中数据的名称也叫url
对于传入的url,先会 escape
,如果有 \\、\、"、$、'
中的一个,都会被加个 \\
最后得到的新 url 会被gbk 编码
而 如果 url 最后不满足这样的形式:
就会报错 Invalid URL
查一查看,有没有数据库的信息
是有的,这个数据库的数据放在/opt/api/database.sqlite3
中
还可以可以看到
报错信息竟然尝试把post进去的内容打印出来!!
受此启发,我想到能不能把服务器上的文件当做post的内容来传入,引起报错,然后看到文件内容?
这时候,思考一下,php向127.0.0.1/api/ping
发出POST 请求的方式有哪些
- curl
- file_get_contents
- fopen
- fsockopen
而其中,能够POST文件的,有curl、file_get_contents
,但是,能仅仅通过控制url来控制传递的文件的,就只有 curl
了!!
也就是说,如果服务器的php用的culr来搞事情,那么攻破这题就很简单了,可以通过curl将database.sqlite3的内容作为POST的参数,传入python,然后通过报错信息,不就能看到文件其中的内容了吗~~~
如果是用的curl,可以想象,php中差不多这样写的:
1 | $ch = init_curl(); |
复习一下php 的 curl怎么POST上传文件
post data 中 /etc/passwd是个字符串,但是 @/etc/passwd 是个文件
/opt/api/database.sqlite3是个二进制文件,我猜,里面可能会有flag的信息吧
我们看一看
果然,报错了,看来二进制数据作为post_data 传到了 python
复制下来到HTML中,打开浏览器看
搜索一下flag、ctf
这样的关键字,最后找到了flag
是 WHCTF{yoooo_Such_A_G00D_@}
总结
还差得远,学就完事儿了