记录一些有意思的bug成因, 积攒经验值. 不定期更新

printf fmt

这种就比较老旧了, 就是如果开发者在使用printf/snprintf之类的函数, 但是fmt是可控的, 就可以通过%n来实现改写栈变量中指向的目的地址的值.

比如:

snprintf(buf, 0x10, fmt, var1, var2)

如果fmt是%0123s%n, 就会把var2指向的值设置为123.

实际的参考例子:

https://labs.watchtowr.com/fortinet-fortigate-cve-2024-23113-a-super-complex-vulnerability-in-a-super-secure-appliance-in-2024/?ref=blog.exploits.club

snprintf

1
2
3
4
char src[9] = "bbbbbbbb";
char dst[8] = "aaaaaa";
int l = snprintf(dst, 0x5, "%s", src);
return l;

一般来说, 这段代码是不会造成安全问题的, 因为并不能溢出dst, 而且函数会自动添加\0截断, 所以也不存在越界读取非0字节的问题.

但是, snprintf的返回值是不截断的长度! 也就是返回了8.

实际例子就是 CVE-2023-4966

1
2
3
4
5
iVar3 = snprintf(print_temp_rule,0x20000,
"{\"issuer\": \"https://%.*s\", \"authorization_endpoint\": \"https://%.*s/oauth/ idp/login\", \"token_endpoint\": \"https://%.*s/oauth/idp/token\", \"jwks_uri\": \"https://%.*s/oauth/idp/certs\", \"response_types_supported\": [\"code\", \"toke n\", \"id_token\"], \"id_token_signing_alg_values_supported\": [\"RS256\"], \"end _session_endpoint\": \"https://%.*s/oauth/idp/logout\", \"frontchannel_logout_sup ported\": true, \"scopes_supported\": [\"openid\", \"ctxs_cc\"], \"claims_support ed\": [\"sub\", \"iss\", \"aud\", \"exp\", \"iat\", \"auth_time\", \"acr\", \"amr \", \"email\", \"given_name\", \"family_name\", \"nickname\"], \"userinfo_endpoin t\": \"https://%.*s/oauth/idp/userinfo\", \"subject_types_supported\": [\"public\"]}"
,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8,uVar5,pbVar8);
authv2_json_resp = 1;
iVar3 = ns_vpn_send_response(param_1,0x100040,print_temp_rule,iVar3);

这里将iVar3作为响应的长度, 导致越界读取了额外的内存, 从而send响应时造成信息泄露.

参考链接: https://www.assetnote.io/resources/research/citrix-bleed-leaking-session-tokens-with-cve-2023-4966

wcsncpy_s(dst,dstlen,src,srclen)

这是个安全拷贝函数, 但是它内部实现(msvcrt.dll)有个异常, 如果dstlen <= srclen, 且src的字符串长度大于等于dstlen, 就会导致崩溃异常.

1
2
3
4
wchar_t src[9] = L"bbbbbb";
wchar_t dst[8] = L"aaaaaaa";
int l = wcsncpy_s(dst, 0x6, src, 6);
printf("ok\n");

这段代码我们就看不到输出”ok”

PathCanonicalize

函数功能是拼接windows的文件路径, 并移除..\, 但是它不会移除../, 如果不正确使用, 存在路径超越问题.

参考案例: 议题 Old School, New Story–Escape from Hyper-V by Path Traversal

strnicmp, wcsnicmp

这类函数有长度限制, 可能错误匹配. 比如 strnicmp(“abc”,”abc123”, 3) 就能通过匹配.

MmProbeAndLockPages 逻辑提权

假如MmProbeAndLockPages 的第二个参数是KernelMode(0), 而构造mdk的va地址来自用户态参数, 那就可以实现直接读写内核地址.

参考: https://big5-sec.github.io/posts/CVE-2023-29360-analysis/

irp->RequestorMode 逻辑问题

irp->RequestorMode irp->PreviousMode. 当内核里调用ZwOpenFile 等Zw开头的api时, irp->PreviousMode就会从UserMode变成KernelMode, 从而绕过一些条件检查. 而irp->RequestorMode 是指原始调用来自用户态还是内核态.

另一种情况是 IoBuildDeviceIoControlRequest , 它后续会调用 IofCallDriver , 默认情况下, 它会把irp->RequestorMode 变为KenrelMode.

参考来源: https://devco.re/blog/2024/08/23/streaming-vulnerabilities-from-windows-kernel-proxying-to-kernel-part1/

IDA 技巧

结构体字段命名

在定义结构体时, 可以在字段命名中添加关键词, 方便审计时提高注意力.

lock1_开头, 表示字段的操作需要上锁.

a_开头, 表示字段是个数组.

_14h结尾, 标识字段在结构体中的偏移, 方便调试时识别.

选择变量, create new struct type...创建结构体时, 如果有符号名称, 可以直接命名成那个名称, 这样有的函数有识别类型的时候, 会自动识别, 省去手动标识.

注意, 如果是c++的代码, 往往子类和父类名称一样, 导致类型识别错误. 需要自行辨别当前的类型应该是父类还是子类.

比如代码:

1
2
3
4
5
6
7
8
9
10
11
12
*((_DWORD *)this + 4) = 1;
*(_QWORD *)this = &CWSDSession::`vftable'{for `IWSDSessionInternal'};
v1 = (char *)this + 80;
*((_DWORD *)this + 13) = 1;
*((_QWORD *)this + 1) = &CWSDSession::`vftable'{for `IWSDMessageBusNotify'};
v2 = 31i64;
*((_QWORD *)this + 3) = 0i64;
*((_QWORD *)this + 4) = 0i64;
*((_QWORD *)this + 5) = 0i64;
*((_DWORD *)this + 12) = 0;
*((_QWORD *)this + 7) = 0i64;
*((_QWORD *)this + 8) = 0i64;

很明显是两个类, 一个类的virtual table 是 IWSDMessageBusNotify, 一个是 IWSDSessionInternal.

因此, 先以this创建结构体, 假设名为a1,

1
2
3
4
5
6
struct a1{
_QWORD field_0;
_QWORD field_8;
....
_QWORD field_40;
};

然后取+8开始字段, 创建新结构体, 假设命名成a2

1
2
3
4
5
struct a2{
_QWORD field_8;
....
_QWORD field_40;
};

将a1重新修改为

1
2
3
4
struct a1{
_QWORD field_0h;
struct a2 field_8h;
}

之后遇到引用子类的函数时, 也好处理了.

会议参考

有时候想发议题了, 发现议题cfp结束了, 就很无语, 列一下我知道会议(毕竟了解的不多, 有遗漏的话, 只是因为我了解的不够多, 还望见谅), 以后可以关注一下

会议名称 2024年举办时间 举办地点 CFP截止日期 演讲支持 备注
CanSecWest 3/20 加拿大 2023/12/30 差旅住宿 一个会场
Zer0Con 4/4 韩国 3/5 $2000+差旅住宿 硬核
Black Hat Asia 4/17 新加坡 2023/12/22 $1000+差旅住宿 多个会场(如果感兴趣议题冲突, 就无法都看)
TyphoonCon 5/30 韩国 3/1 差旅住宿
OffensiveCon 5/10 德国柏林 4/2 演讲费1000欧元+差旅住宿 硬核
GeekCon 5/25 不固定(24年新加坡) 4/20 $1200+差旅住宿
OffByOne 6/26 新加坡 3/2 演讲费不详+差旅住宿
REcon 6/28 加拿大 4/26 $1000演讲费+差旅住宿
Black Hat USA 8/7 美国洛杉矶 4/10 $1000演讲费+差旅住宿
HITBSecConf BangKok 8/29 曼谷 4/30 演讲费不详+差旅住宿 hitb 有多个会议, 这里是其中一个, 不同会议时间和地点都不一样
PoC 11月 韩国 10/15 不详
Black Hat Euro 12/9 英国伦敦 不确定 $1000演讲费+差旅住宿
hexacon 10/4 法国巴黎 6月或者5月 不确定
HITCON 8/19 台湾 不确定 不确定
MOSEC 11月 上海 不清楚 不清楚
districtcon 2025/2/21 美国华盛顿 2024/11/01 不清楚
SAS2024 2024/10/21 印尼巴厘岛 2024/8/15 不清楚

其它的我觉得和我想象的技术会议有点不太一样, 有兴趣的可以自己关注一下, 比如: DEFCON, InfoSec

其它会议: vxcon香港, rootcon菲律宾, GreHack法国,