一些Linux指令

SSH

SSH(Secure Shell)是一种网络协议,用于安全地远程登录到计算机系统。SSH 主要用于以下场景:

远程命令行登录
文件传输(通过 SFTP 或 SCP)
端口转发

使用格式:

ssh ctfshow@题目地址 -p题目端口号

ls

ls 命令用于列出目录内容

eg:

  • ls:列出当前目录的内容。

  • ls -l:以长格式列出当前目录的内容,显示文件的详细信息。

  • ls -a:列出当前目录的所有文件,包括隐藏文件(以点开头的文件)。

  • ls /path/to/directory/:列出指定目录的内容。

    注:ls后加 / 是为了明确指定路径避免歧义

nc

nc(Netcat)是一个功能强大的网络工具,用于读取和写入网络连接

看起来你正在使用 gdb(GNU 调试器)来调试一个程序。gdb 是一个强大的工具,可以帮助你分析和调试程序的行为。如果你有具体的调试需求或遇到问题,请告诉我更多细节,我可以提供进一步的帮助。

echo

echo 是一个常用的命令行工具,用于将指定的文本输出到标准输出设备(通常是终端,也可以是指定文件)。这个命令非常简单但功能强大,常用于脚本编写和日常操作中的调试信息显示。

echo [选项] [字符串]

利用echo将CTFshow写入key文件:

1
echo "CTFshow">key  //>为重定向,可以理解为重定向了标准输出设备

常见选项:

-n : 不输出末尾的换行符

-e : 启用对反斜杠转义字符的支持

exec

使用 exec 可以让新的命令完全替代当前的 shell 进程,而不仅仅是作为一个子进程运行。

exec [选项] 命令 [参数…]

当获得一个shell后可使用exec执行特定命令:

程序给了我们一个shell但是不是交互式的我们可以使用了exec函数来执行sh命令,并使用1>&0来进行输出重定向,即exec sh 1>&0这个命令将标准输出重定向到标准输入,实际上就是将命令的输出发送到后续命令的输入。具体来说,1>&0中的1表示标准输出,0表示标准输入。通过将标准输出重定向到标准输入,可以实现将命令的输出作为后续命令的输入。这样可以在执行sh命令后,进入一个交互式的Shl环境,可以在该环境中执行命令并与用户进行交互。
也可以直接exec cat/ctf* 1>&0将cat/ctf*命令的输出发送到标准输入,实际上就是将命令的输
出再次输出到屏幕上。

编译与链接

在编译和链接命令中,-o 是一个常用的选项,用于指定输出文件的名称。

nasm

nasm是一种汇编语言编译器,用于将低级的汇编代码转换成机器码。它支持多种输出格式,包括但不限于ELF、COFF和二进制文件等。

利用nasm将.asm(文本文件)编译成ELF格式的.o(对象文件):

1
nasm -f elf flag.asm -o flag.o
  • -f elf: 指定输出文件的格式为ELF(Executable and Linkable Format),这是Linux系统常用的二进制文件格式。
  • flag.asm: 输入的汇编源代码文件。
  • -o flag.o: 指定输出的文件名为 flag.o,这是一个对象文件。

ld

ld为链接器,用于将对象文件链接成一个可执行文件

1
ld -m elf_i386 -o flag flag.o
  • -m elf_i386: 指定目标架构为i386(即32位x86架构)。这确保生成的可执行文件适用于32位系统。
  • -o flag: 指定输出的可执行文件名为 flag
  • flag.o: 输入的对象文件。

常见的 gdb 命令:

启动程序

gdb

1
run

查看当前进程的虚拟内存映射

这将显示程序的各个内存段及其地址范围、权限等信息。

gdb

1
vmmap

寄存器及寻址方式

汇编指令与寄存器

  • mov:将值从一个寄存器移动到另一个寄存器或内存地址。
  • push:将寄存器的值压入栈中,ESP/ESP减少。
  • pop:从栈中弹出值到寄存器,ESP/ESP增加。
  • call:调用函数,将返回地址压入栈中。
  • ret:从函数返回,从栈中弹出返回地址到EIP/RIP。

立即寻址方式

​ mov eax, 11 ; 将11赋值给eax
​ add eax, 114504 ; eax加上114504
​ sub eax, 1 ; eax减去1

最后eax的值为11+114504-1=114514

寄存器寻址方式

​ mov ebx, 0x36d ; 将0x36d赋值给ebx
​ mov edx, ebx ; 将ebx的值赋值给edx

直接寻址方式(存地址)

​ mov ecx, msg ; 将msg的地址赋值给ecx

eg:mov ecx, dword_80490E8

dword_80490E8 是一个 32 位的双字(double word),其值是一个内存地址。这条指令的作用是将内存地址 0x80490E8 直接赋值给寄存器 ecx。这意味着 ecx 现在存储的是这个地址本身,而不是该地址所指向的数据。

寄存器间接寻址方式(存对应地址上所对应的值)

​ mov esi, msg ; 将msg的地址赋值给esi
​ mov eax, [esi] ; 将esi所指向的地址的值赋值给eax

方括号 [ ] 表示间接寻址,即访问的是括号内表达式所指向的内存地址中的内容,而不是表达式本身。

.data:080490E8 57 65 6C 63 dword_80490E8 dd 636C6557h *这段代码表示的是在地址 080490E8 处的数据段中定义了一个双字(dword)变量 dword_80490E8,其值为 636C6557h*其中h为汇编中表示16进制数的后缀

寄存器相对寻址方式

​ mov ecx, msg ; 将msg的地址赋值给ecx
​ add ecx, 4 ; 将ecx 寄存器中的值增加4(地址加4)
​ mov eax, [ecx] ; 将ecx所指向的地址的值赋值给eax

基址变址寻址方式

​ mov ecx, msg ; 将msg的地址赋值给ecx
​ mov edx, 2 ; 将2赋值给edx
​ mov eax, [ecx + edx*2] ; 将ecx+edx*2所指向的地址的值赋值给eax

相对基址变址寻址方式

​ mov ecx, msg ; 将msg的地址赋值给ecx
​ mov edx, 1 ; 将1赋值给edx
​ add ecx, 8 ; 将ecx加上8
​ mov eax, [ecx + edx*2 - 6] ; 将ecx+edx*2-6所指向的地址的值赋值给eax

gcc编译文件

1
2
gcc -o hello hello.c
gcc flag.s -o flag

关闭所有保护:

  1. **-fno-stack-protector**:

    • 禁用堆栈保护器(Stack Protector),防止在函数调用中插入额外的检查代码。
  2. **-z execstack**:

  • 允许堆栈执行,禁用 NX 位(No-eXecute)保护。
  1. **-Wl,-z,norelro**:

    • 禁用只读重定位表(RELRO),使数据段不被标记为只读。
  2. **-D_FORTIFY_SOURCE=0**:

  • 禁用源代码级别的安全强化功能。
  1. **-no-pie**:
  • 禁用位置独立代码(PIE),生成非位置独立的可执行文件,不利于 ASLR 的有效性。

开启所有保护:

  • **-fstack-protector-all**:启用全面的堆栈保护器。
  • **-z relro**:启用部分 RELRO。
  • **-z now**:启用完全 RELRO。
  • **-D_FORTIFY_SOURCE=2**:启用源代码级别的强化。
  • **-pie**:生成位置独立的可执行文件(PIE),有助于 ASLR。
  • **-Wl,-z,noexecstack**:确保堆栈不可执行(默认情况下通常是这样的)。

命令注入获取shell

下面这段为连上靶机后执行的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
How much do you know about Linux commands? 

1.id
2.ls
3.cat /ctfshow_flag
4.su
5.exit

Enter the command you want choose:(1.2.3.4 or 5)

2
Which directory?('/','./' or the directiry you want?)

使用;分隔ls并根据下方源码中的获取输入的漏洞送/bin/sh进去,如果不用;分隔则只会尝试列出/bin/sh目录。

1
2
3
4
5
6
7
case 2:
puts("Which directory?('/','./' or the directiry you want?)");
read(0, buf, 0xAuLL);
strcat(dest, buf);
system(dest);
puts("Execution succeeded!");
break;

当输入2时会执行上面的代码,其中read获取输入,0xAuLL对应十进制值为10故最多可输入10个字节,strcat将buf的值赋值给dest,dest又在system中故可输入/bin/sh获取shell。

;为分隔command1;command;command三条指令会按照顺序执行,并且前面的指令执行是否成功不会影响后边指令的执行。

command1&command 两条指令会在后台同时执行。

文件输出流

文件输出流(File Output Stream)是一种用于将数据写入到文件中的输入/输出流,

  • 基本功能:文件输出流主要用于创建新文件或将数据追加到现有文件。

  • 工作原理:当你创建一个文件输出流对象并指定目标文件后,你可以通过该对象的方法来写入数据。这些方法包括 write 方法,可以接受单个字节或字节数组作为参数。

关闭输出流是一个非常重要的步骤,它确保了所有缓冲的数据都被正确地写入到目标文件,并且释放了系统资源。具体来说,关闭输出流会有以下几个效果:

  1. 刷新缓冲区:如果输出流有内部缓冲区(大多数情况下都有),关闭流会强制将缓冲区中的所有未写入数据写入到目标文件中。这确保了没有任何数据丢失。
  2. 释放资源:操作系统对打开的文件描述符数量有限制。如果不及时关闭输出流,可能会导致资源泄露,最终耗尽可用的文件描述符,从而影响程序的正常运行。
  3. 防止数据损坏:在某些情况下,不关闭输出流可能导致数据部分写入或完全未写入,从而造成数据损坏或不完整。
  4. 提高性能:及时关闭不再需要的输出流可以减少不必要的内存占用和系统开销,有助于提高程序的整体性能。
  5. 异常处理:即使在发生异常的情况下,也应该尽量关闭输出流。使用 try-with-resources 语句可以自动管理资源的关闭,简化代码并减少错误发生的可能性。

设置ALSR保护参数

ASLR(Address Space Layout Randomization)是一种操作系统级别的安全保护机制,旨在增加软件系统的安全性。它通过随机化程序在内存中的布局,使得攻击者难以准确地确定关键代码和数据的位置,从而增加了利用软件漏洞进行攻击的难度。

开启不同等级会有不同的效果:
1.内存布局随机化:ASLR的主要目标是随机化程序的内存布局。在传统的内存布局中,不同的库和模块通常会在固定的内存位置上加载,攻击者可以利用这种可预测性来定位和利用漏洞。ASLR通过随机化这些模块的加载地址,使得攻击者无法准确地确定内存中的关键数据结构和
代码的位置。
2.地址空间范围的随机化:ASLR还会随机化进程的地址空间范围。在传统的地址空间中,栈、堆、代码段和数据段通常会被分配到固定的地址范围中。ASLR会随机选择地址空间的起始位置和大小,从而使得这些重要的内存区域在每次运行时都有不同的位置。
3.随机偏移量:ASLR会引入随机偏移量,将程序和模块在内存中的相对位置随机化。这意味着每个模块的实际地址是相对于一个随机基址偏移的,而不是绝对地址。攻击者需要在运行时发现这些偏移量,才能准确地定位和利用漏洞。
4.堆和栈随机化:ASLR也会对堆和栈进行随机化。堆随机化会在每次分配内存时选择不同的起始地址,使得攻击者无法准确地预测堆上对象的位置。栈随机化会随机选择栈帧的起始位置,使得攻击者无法轻易地覆盖返回地址或控制程序流程。

在linux中,ALSR的全局配置/proc/sys/kernel/randomize_va_space(这是一个用于控制地址随机化的文件)有三种情况

1

修改一个文件的ASLR:

首先将终端目录定位到文件,或者直接在文件处打开终端

1
2
3
4
5
cat /proc/sys/kernel/randomize_va_space 
#查看当前ASLR的操作数
sudo sh -c 'echo 1 > /proc/sys/kernel/randomize_va_space'
#将此文件的ASLR操作数改为0
#此处sh-c是为了在子shell中执行命令,这样sudo会为整个命令提供超级用户权限

在未开启PIE的情况下不论ASLR操作数是多少函数的地址都不会改变。

地址空间布局随机化(Address Space Layout Randomization, ASLR)和位置无关可执行文件(Position-Independent Executable, PIE)是两个重要的安全机制。