QEMU 引入 NX 到 qemu-user 中(栈不可执行)

QEMU 引入 NX 到 qemu-user 中(栈不可执行)

RocketDev

qemu-user的nx出现了?

在网鼎杯决赛,我还利用过qemu-user没有nx的特性,在栈上执行shellcode, 然而在最近的湾区杯,有师傅惊讶地发现本地的qemu-user不能在栈上执行shellcode了。 我写了一个简单的示例,用来复现这个问题(使用-z execstack来给栈加可执行权限)。

1
2
3
4
5
6
7
8
int main(int argc, char **argv) {
// mov eax, 60; xor edi, edi; syscall;
// exit(0);
unsigned char buf[64] = "\xb8<\0\0\0\x31\xff\x0f\x05";
void (*myexit)(void) = (void (*)(void))buf;
myexit();
return 0;
}

编译后运行,没开nx会正常退出,开了会 SIGSEGV ,这很正常。接下来使用qemu-x86_64 来运行,和直接运行没有区别,同样会 SIGSEGV 。可是去年我明明用这个特性做出过题啊, 这是怎么回事?

群里师傅发现,远程环境确实没有nx,而且qemu-user是没有ASLR的,因此甚至不用泄露信息。 然而,这些“优良的特性”在新版qemu上荡然无存。接下来的任务就是找到哪个版本引入了变更, 在目标靶机上安装的qemu版本是多少时,需要考虑更加复杂的方案。

拉取源码定位差异

QEMU的仓库拉取最新的源码仓库,然后编译测试特性, 按大版本标签做二分查找,最后定位到v7.2.0b34b42 commit加入了对ELF中exec_stack flag的判断。也就是说,从 qemu-user v7.2.0 开始,就不能直接栈溢出, 跳到栈上运行了。那么对应到Ubuntu版本,我做了下面这张图,简而言之,从 Ubuntu 24.04 开始, 自动开启NX。

其他系统的qemu版本可以在Repology上找到。

ASLR也有影响?

在最近的变更中,加入了“ASLR”,照理来说原来的版本,程序基地址、库基地址都是固定的, 然而,在x86_64上是这样,aarch64上却不是,在手机上使用qemu-user,虽然是老版本, 但是基地址都不同。因此这里就不罗列信息了。

参考

  1. QEMU/QEMU - GitLab
  2. Merge tag of rth7680/qemu into staging
  3. qemu package versions - Repology
  • 标题: QEMU 引入 NX 到 qemu-user 中(栈不可执行)
  • 作者: RocketDev
  • 创建于 : 2025-10-15 19:00:00
  • 更新于 : 2025-10-15 19:00:00
  • 链接: https://rocketma.dev/2025/10/15/qemu-user-nx/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
QEMU 引入 NX 到 qemu-user 中(栈不可执行)