ISCC个人挑战赛之练武题部分WP
MISC
好看的维吾尔族小姐姐
附件下载解压出来是一个没有后缀的名为“古力娜扎”的文件,使用winhex打开:
根据文件头判断是PNG图片,将文件后缀进行更改,得到一张图片:
图片很小,看起来比例也有点怪,根据经验怀疑是更改了大小,所以直接上010editor把大小改一下:
在这里调用png的模板,把高度改的大一点,之后保存发现图片的下方藏着一张”二维码”:
看起来像传统意义上的二维码,实际上又不是。这是一种特殊形式的二维码:Data Matrix码。通过一些其他的二维码扫描软件可以得到一串比较特殊的代码:
这不就是反过来的unicode么!这时候才联想到题目的提示:维吾尔族同胞的说话方式,莫非是反着说?不太了解,把字符串反过来unicode解码拿到flag:
WEB
羊了个羊
题目上来玩游戏啊,第一关第二关无穷无尽。看到上面有三个按钮,充值关卡和上一关均正常使用,冲关秘技被disable了,查看一下页面源码:
1 | <button class="btn" @click="handleIscc" disabled = true>冲关秘技</button> |
这个button绑定了一个点击事件handleIscc,既然如此就在js中找一找这个:
1 | const handleIscc = () =>{ |
也能草草看到一些逻辑,通关100关才给flagQwQ,那就继续向下分析:
1 | if (!hasCards.length && level >= config.maxLevel) { |
这里首先一个判断是否还有剩余的没有消除掉的卡片,如果没有并且此时的层数大于设定的层数就会alert这段base64加密后的字符串,解密之后即为flag。
小周的密码锁
题目打开是四个表项,前三个已经分别填好了123,随便填一个之后再burpsuite中抓到验证的包,送到intruder模块单字符开爆!发包间隔要高,我试的1200ms间隔(没挂代理别给我ip封了)。说来也是碰巧,提交的get请求有两项:
按理说应该爆第一个password的来着,结果第一次爆成了password2,误打误撞一次成功:
得到password2是5,直接访问得到php源码:
1 |
|
开始分析,首先定义了四个函数MyHashCode、intval40、Checked以及SecurityCheck。之后get接收变量username、sha1以及“sha2”,这里sha2标引好是因为变量名并不是sha2:
在vscode中可以看到get的变量名称有些怪,这里涉及到一些特殊的unicode字符,这些字符控制着整体字符串的打印方式,可以参考:
解决办法就是提前进行url编码,传入时直接传入url编码:
1 |
|
ok,下面继续分析。因为我们已经get传入了password,所以第一层if可以进入,并且第二层的password2=5也已经被我们爆出来了,我们需要进入到第二层if的else分支,password2不为5即可。之后第三层if需要传入username,sha1,以及那串特殊字符,进入后调用了SecurityCheck函数,该函数首先判断sha1是否全为小写字母,sha2是否全为大写字母,满足条件后将sha1转成大写,sha2转成小写,user转成大写,返回sha1和sha2的逐位异或和转大写的user。
第四层的if有些棘手,需要让user的sha1值的后六位等于a05c53,同时返回的异或值的sha1值的后六位也等于a05c53。至于user可以写个脚本用递增的数字转字符串计算sha1进行碰撞,很快就能拿到第一个符合条件的:
user=14987637
第二个的话只需要构造出sha1异或sha2等于user的值即可,随便写了个脚本跑出一张表:
摘取大写字符^小写字母=数字的项逐个拼接构造,得到众多结果中的一个:
$sha1 = ‘BBCBEGCE’;
$sha2 = ‘svzzrqpr’;
因为这个函数还会大小写相互转换,所以这里要对大小写提前转换一下,上面的是没转换前的。
之后就是第五层的if了。第五层需要传入password,要求是password中不能出现ISCC并且将其传入后得到的结果与ISCCNOTHARD传入后相同。简单分析一下这个MyHashCode函数。这个函数逐位取传入的字符串,每次将hash变量乘以40传入intval40函数并将取到的字符的ascii码相加作为参数传入intval40函数,返回值即为本轮循环后的hash值,尝试本地运行找出每次for循环后的hash值:
73|3003|120187|4807547|192301958|7692078399|307683136044|12307325441832|492293017673345|19691720706933882|787668828277355348|
既然不能出现ISCC,那么就从这里作为切入点。看看如果不使用ISCC,能否构造出能够替换的字符串。至于intval40这个函数,看一下chatGPT的解释:
这段代码是一个PHP函数,名为intval40,它的作用是将一个64位整数转换为40位整数。具体实现是通过判断最高位是否为1来确定是否需要进行补码操作,然后将结果返回。其中,如果最高位为1,则需要进行补码操作,将其转换为相应的负数。最后,返回40位整数的值。
最高位不是1时直接返回,不会对传入值造成任何影响,那么就来测试一下,看看在开头的处理ISCC字符串时是否有影响:
0000000000110000000000
0代表直接返回,1代表进行补码操作,处理字符串时每个字符调用两次intval40,因此前面处理ISCC时intval40没有对hash的值造成任何影响,这样就使题目更加简单了。我们的思路现在变成了能否构造字符串替换ISCC。已知在处理ISCC时intval40不会对hash的值造成影响,因此只要我们构造的字符串的开头几个字符生成的hash值在某一阶段与ISCCNOTHARD的开头相同,并且其后的字符与其保持一致,就能够成功绕过这个限制条件,如何构造?已知开头的字符串ISCC四个阶段的hash值分别为73|3003|120187|4807547,我们能否构造出第二阶段的hash值等于73?hash的初值为0,第一次intval40的结果为0,与第一个字符的ascii值相加传入intval40得到第一阶段的hash值即为第一个字符的hash值,如果要在第二阶段的值为73的话,第二个字符的ascii值应为33,ascii中是叹号,因此我们可以将ISCCNOTHARD中的I替换为ascii为1的字符加上叹号,ascii为1的字符是非可见字符,经过url编码后为%01,传入即可拿到flag,最终payload:
1 | password=%01!SCCNOTHARD&password2=1&username=14987637&sha1=bbcbegce&%E2%80%AE%E2%81%A6%2F%2F%73%68%61%32%E2%81%A9%E2%81%A6%73%68%61%32=SVZZRQPR |
chatGGG
开头一个简易的对话界面,感觉可能是模板注入,输入双花括号之后符号会消失,+也会转义成“加”等等,还是做了一些过滤的。
SSTI学得比较菜,在一些过滤绕过的文章中找到一些灵感
https://blog.csdn.net/weixin_52635170/article/details/129850863
使用变量设置以及拼接的方式进行绕过,不妨从构造好的payload入手:
1 | ask={%set pop=dict(po=a,p=b)|join%} |
由于做了一些特殊符号以及单词的过滤,因此需要进行拼接构造或从其他位置取得,例如下划线,则是从lipsum|string|list中取得,lipsum是flask的一个方法,string则是转化为字符串,list则是将字符串转化为列表
第24个字符为下划线,因此使用pop(24)可以截取到下划线。
1 | 1. lipsum|attr("__globals__") 相当于 lipsum.__globals__ |
实战题
顺便附上实战第一阶段吧,第一阶段用到了cve-2018-76602,直接在网上找了个现成的poc直接打,账号密码弱口令(drupal,drupal)