2022年11月

使用这个开源工具,即使是批量校正图像也很容易。

多年前,在翻阅一家旧书店的书架上的内容时,我偶然发现了一本名为 《UNIX System Command Summary for Berkeley 4.2 & 4.3 BSD》 的小册子,由 Specialized Systems Consultants 出版。我买它是出于好奇,因为它已经有将近 20 年的历史了,但仍然在很大程度上适用于现代 Linux 和 BSD。

无论是当时还是现在,我都很开心。一本写于 1986 年的小册子在 2016 年仍然很重要,而同一个书架上关于专有操作系统的书籍并不值得印刷它们的纸张。(想一想:你认为什么技术可以在僵尸末日中幸存下来?)这本小册子已经放在我自己的书架上好几年了,但我突然想到可能值得对这个作品做一点数字保存,所以我决定扫描这本小册子来创建一本 CBZ 电子书

使用 Skanlite 进行扫描很容易,但很耗时。然而,当我完成后,我发现有些页面不是很平整。

A page of text, including a table of contents and a glossary, that is crooked and distorted

在打印中,这称为配准问题,这意味着打印内容的位置在页面上的方向不正确。

ImageMagick

ImageMagick 是基于终端的非交互式图形编辑器。尝试在无图形环境(如纯文本终端)中编辑图形似乎违反直觉,但实际上很常见。例如,当你将图像上传到 Web 应用用作个人资料图片时,应用服务器上的脚本可能会使用 ImageMagick 或其库处理你的图像。非交互式编辑器的优点是你可以制定需要对示例图像执行的操作,然后只需按一下按钮即可将这些效果应用于数百个其他图像。

ImageMagick 通常与其他图形编辑器一样强大,只要你花时间了解它的许多功能以及如何组合它们以实现所需的效果。在这种情况下,我想旋转歪斜的页面。在搜索了 ImageMagick 的文档后,我发现我需要的解决方案的 ImageMagick 术语称为纠偏。将你的术语与其他人的术语保持一致对于你不知道的任何事情都是一个挑战,因此当你使用 ImageMagick(或其他任何东西)时,请记住,你描述问题或解决方案的用词可能和别人不一样。

要使用 ImageMagick 对带有弯曲文本的图像进行校正:

$ convert page_0052.webp -deskew25% fix_0052.webp

-deskew 选项表示可接受偏差的阈值。通过跟踪看似字母的对象的峰谷来确定倾斜。根据扫描的弯曲程度,你可能需要多于或少于 25% 的阈值。我已经达到了 80%,到目前为止,低于 25% 没用效果。

结果如下:

The same page of text, now with the text properly aligned

修复了!将其应用于文档的剩余 55 页以修复倾斜的页面,而对已经笔直的页面不做任何事情。换句话说,由于我的阈值设置,在不需要调整的页面上运行此命令是安全的。

使用 ImageMagick 裁剪图像

在纠正了歪斜之后,因为我扫描每一页都比必要的范围要多,以防止意外切断单词,我认为裁剪我纠正的页面是有意义的。我很高兴在页边空白处保留一些空间,但没有以前那么多。我经常使用 ImageMagick 的“裁剪”功能来处理这个网站上的图像,所以我很熟悉这个选项。但是,我需要确定如何裁剪每一页。

首先,我需要图像的大小:

$ identify fixed_0052.webp
WEBP 1128x2593 1128x2593+0+08-bit sRGB 114732B 0.020u 0:00.021

知道尺寸后,我能够对我可以承受的丢失多少像素做出一些估计。经过几次试运行,我得到了这个:

convert fix_0052.webp -gravity Center -crop 950x2450+0+0 crop_0052.webp

这并不完全适合,但当我将它应用于册子中的其他图像时,它被证明很重要。这些页面的内容和扫描仪位置各不相同,所以我很高兴给每一页一点空余空间。

这是校正和裁剪的图像:

The same page of text, with the previous fixes applied and crooked white margins around the page cropped out.

使用开源批量编辑图像

ImageMagick 的美妙之处在于,当你确定了修复图像的公式,你就可以将该修复应用于需要相同修复的所有图像。我使用 GNU Parallel 执行此操作,它使用我所有的 CPU 内核来完成数百页的图像校正。这并不需要很长时间,而且结果不言而喻。更重要的是,我已经有了一个 UNIX 历史上有趣作品的数字档案。


via: https://opensource.com/article/22/11/fixing-scanned-images-imagemagick

作者:Seth Kenlon 选题:lkxed 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这些年来,我通过这些开源资源提高了我的 Python 技能。

我最近决定进一步学习 Python,以便提高我的教学技能,拓宽我的学生的视野。在这个过程中,我发现了这些优秀的资源,让我学习新的代码,并提高了对 Python 的整体理解。

1、《教孩子学编程 Python 语言版》

我的 Python 之旅大约是 7 年前开始的,当时我发现了 Apple LOGO 和 Python 中的 Turtle 模块 之间的联系。当时使用的 Linux 计算机的默认 Python 版本为 Python 2.7,我很快发现我想使用 Python 3。我成功地安装了它,并开始使用 Turtle 模块编写一些简单的程序。在阅读 Dr. Bryson Payne 的 《教孩子学编程 Python 语言版》 之后,我意识到 Python 不仅仅是 Turtle。那时我安装了 IDLE

2、IDLE

在使用 IDLE 工作的过程中,交互式界面优化了我的体验,并让我有足够的信心来考虑向学生教授 Python。我志愿帮助我社区中的一群在家学习的孩子,很快我发现自己在教授一个有十六个孩子的班级!我很高兴他们的父母同意帮助我,否则我想我会被压垮。这个经历激发了我学习更多的欲望,以便我可以教授更多。

3.、Mu 编辑器

2018 年春天,我参加了 PyConUS。我听了一场由中学老师 Nicholas Tollervey 主讲的演讲,他为学龄前儿童编写了一个 Python 开发环境。Mu 编辑器 内置了一个可以帮助我找到代码中的错误的 质检工具 Linter 。Mu 帮助我提高了我的编码技能,我也能够与学生分享这些技能,他们也从中受益。

我的自信和经验增长后,我希望与更多的学生分享 Python 之旅。我与其他人合作撰写了一个申请书,以教授一个使用树莓派 4 和 Python 的课程。疫情打断了这个计划。在此期间,树莓派基金会发布了树莓派 400。2021 年春天,我使用了前一年开发的材料和一个来自当地图书馆的慷慨的资助,来 教授两组 学生如何编程。这个活动非常成功并在今年再次举办。

4、Codium

几年前,我了解到微软的 VS Code 是一个可以在 Linux 上使用的开源代码编辑器。我最近才了解到,如何在 VS Code 中配置和使用 Python 虚拟环境。我的问题在一篇 关于虚拟环境的文章 中得到了解答,这让我可以知道如何在 Linux 计算机上设置和配置 Python 虚拟环境。大约在同一时间,我发现了 Codium,一个围绕 VS Code 构建的社区项目。

现在我希望与我的学生分享 VS Codium 的体验,并让他们对 Python 的理解不再局限于 Turtle 模块。这种学习的热情让我寻找开源且可以在互联网上随意获得的教学资源。

5、《Python 编程练习,简单解释》

Python 编程快速上手 让繁琐工作自动化》 这本书是我最喜欢的一本书。现在,作者已经发布了 《Python 编程练习,简单解释》。这两本书都可以免费在线阅读,并且都采用了知识共享许可证。

6、《每个人都可以使用 Python》

Dr. Charles Severance 在 2017 年发布了 《每个人都可以使用 Python》,我非常推荐这本书。他为像我这样的有抱负的程序员提供了简短的课程。课程的代码可以在 GitHub 上找到,所以你可以下载它并在自己的计算机或学校网络上安装它。

7. Python 视频

最近,我了解到 Jay LaCroix 在 YouTube 上有一系列精彩的视频,其中包括 28 个免费视频,从 Python 基础开始,涵盖了 Python 编程 的全面介绍。最重要的是,他使用的是 Linux 计算机,因此他的课程特别适合 Linux 编程环境。这些视频的其中一个收获是学习如何使用 nano 作为编程环境,它默认情况下包含在大多数 Linux 发行版中。

你的学习之路

此处提到的这七个资源帮助我成长为一名程序员,它们都是开源的并可以与其他人分享。你是如何提高编程技能的?你有什么要分享的吗?在评论中告诉我们。


via: https://opensource.com/article/22/11/learn-python

作者:Don Watkins 选题:lkxed 译者:Cubik65536 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

一半的 macOS 恶意软件都来自一个“杀毒软件”

Elastic 安全实验室发现,一半 macOS 恶意软件来自 MacKeeper。讽刺的是,MacKeeper 声称 “以零努力保持你的 Mac 清洁和安全”。该程序可以被威胁者滥用,因为它有广泛的权限和对进程和文件的访问。这意味着,一个旨在保持 Mac 安全不受网络威胁的程序可能使你的系统处于危险之中。 MacKeeper 也以难以完全卸载而著称。然而,Mac 仍然是恶意软件最少的操作系统,研究发现只有 6.2% 的恶意软件出现在 macOS 上,而 Windows 和 Linux 上则分别为 54.4% 和 39.4%。

消息来源:Neowin
老王点评:这可真够讽刺的,一个杀毒软件反而是最大的黑窝。

开源推动 5G 占据了 50% 的电信市场

5G 部署现在已经超过 50% 的电信市场规模,这得益于开源。Linux 基金会称,在这一切的背后,“是向开放网络和框架的彻底转变。无论经济和政治风向如何,这种转变都在继续。事实上,开源可能是唯一没有受到影响的领域,因为它有能力跨越国界和边界来做需要做的事情。”据一些分析师的说法,到 2030 年,5G 的经济价值将达到 7 万亿美元。

消息来源:ZDNet
老王点评:开源居然对 5G 的推广有这么大的作用,这是有些想不到。

Mozilla 收入更多样,但仍然主要依靠谷歌

Mozilla 今天发布了其年度《Mozilla 状况》报告,2021 年,Mozilla 公司从搜索合作、订阅和广告收入中获得了 5.85 亿美元,比前一年增长了 25%。除了主要来自谷歌的搜索合作的收入之外,来自 Mozilla VPN、Mozilla MDN Plus、Pocket 等新产品的收入为 5700 万美元,与前一年相比增长了 125%。

消息来源:Tech Crunch
老王点评:虽然 Mozilla 也有一些让人批评的地方,但是这已经是自由开源世界不多的重要旗舰了。

本文讲述如何一步步在 Linux 上安装 AWS CLI(命令行工具)。

AWS CLI 是一个能够和 AWS 账户进行交互的命令行程序。开发者和系统管理员用它管理日常的活动和自动化。

准备环节

  • 安装好的 Linux 系统
  • 具有管理员权限的 sudo 账户
  • 能够联网

现在让我们开始安装:

1、下载安装文件

打开终端使用 curl 命令下载 AWS CLI 的安装文件:

$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

以上命令会在当前工作目录下载一个 awscliv2.zip 的文件。

使用 ls 命令 确认当前下载下来的文件:

$ ls -l awscliv2.zip
-rw-rw-r-- 1 linuxtechi linuxtechi 47244662 Oct 20 10:53 awscliv2.zip
$

2、解压缩下载的文件

使用 unzip 命令 解压安装包:

$ unzip awscliv2.zip

它会在当前目录创建一个 aws 文件夹,把解压好的文件放进去:

$ ls -ld aws
drwxr-xr-x 3 linuxtechi linuxtechi 4096 Oct 19 17:18 aws
$

3、运行安装脚本

使用以下命令运行安装脚本:

$ sudo ./aws/install

脚本会把所有安装的文件放到 /usr/local/aws-cli 目录下,然后创建一个链接文件到 /usr/local/bin 目录。

4、检查 AWS CLI 的版本

运行以下脚本检查版本:

$ aws --version
aws-cli/2.8.4 Python/3.9.11 Linux/5.15.0-48-generic exe/x86_64.ubuntu.22 prompt/off
$

5、配置 AWS CLI

为了验证 AWS CLI 是否安装正确,开始配置 AWS CLI:

登录你的 AWS 管理控制台,取得 AWS 访问密钥 ID Access Key ID 安全访问密钥 Secret Access Key

如果还没完成创建,请先创建,并把它们复制到安全的地方。

然后回到命令行,运行以下命令:

$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxx
Default region name [None]: us-west-2
Default output format [None]: json
$

以上的证书会被保存到这个文件:

$ cat  ~/.aws/credentials

上面的命令的输出:

运行 aws 命令列出你账户中的 s3 储存和 VPC:

$ aws s3 ls
$ aws ec2 describe-vpcs

输出如下:

成功输出内容,说明你的 AWS CLI 已经配置完成。

这就是这篇文章的全部内容,请在下面的评论区发表你的疑问和反馈。


via: https://www.linuxtechi.com/how-to-install-aws-cli-on-linux/

作者:Pradeep Kumar 选题:lkxed 译者:littlebirdnest 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

这篇文章能让你了解如何使用 Checksec ,来识别一个可执行文件的安全属性,了解安全属性的含义,并知道如何使用它们。

编译源代码会生成一个二进制文件(LCTT 译注:即 .o 文件)。在编译期间,你可以向 gcc 编译器提供 标志 flags ,以启用或禁用二进制文件的某些属性,这些属性与安全性相关。

Checksec 是一个漂亮的小工具,同时它也是一个 shell 脚本。Checksec 可以识别编译时构建到二进制文件中的安全属性。编译器可能会默认启用一些安全属性,你也可以提供特定的标志,来启用其他的安全属性。

本文将介绍如何使用 Checksec ,来识别二进制文件的安全属性,包括:

  1. Checksec 在查找有关安全属性的信息时,使用了什么底层的命令
  2. 在将源代码编译成二进制文件时,如何使用 GNU 编译器套件 GNU Compiler Collection (即 GCC)来启用安全属性

安装 checksec

要在 Fedora 和其他基于 RPM 的 Linux 系统上,安装 Checksec,请使用以下命令:

$ sudo dnf install checksec

对于基于 Debian 的 Linux 发行版,使用对应的 apt 命令,来安装 Checksec。

$ sudo apt install checksec

shell 脚本

在安装完 Checksec 后,能够发现 Checksec 是一个单文件的 shell 脚本,它位于 /usr/bin/checksec,并且这个文件挺大的。Checksec 的一个优点是你可以通过快速通读这个 shell 脚本,从而了解 Checksec 的执行原理、明白所有能查找有关二进制文件或可执行文件的安全属性的系统命令

$ file /usr/bin/checksec
/usr/bin/checksec: Bourne-Again shell script, ASCII text executable, with very long lines

$ wc -l /usr/bin/checksec
2111 /usr/bin/checksec

以下的命令展示了如何对你每天都会使用的:ls 命令的二进制文件运行 Checksec。Checksec 命令的格式是:checksec --file=,后面再跟上二进制文件的绝对路径:

$ checksec --file=/usr/bin/ls
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      Canary found      NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols        Yes   5       17              /usr/bin/ls

当你在终端中对某个二进制文件运行 Checksec 时,你会看到安全属性有颜色上的区分,显示什么是好的安全属性(绿色),什么可能不是好的安全属性(红色)。我在这里说 “可能” 是因为即使有些安全属性是红色的,也不一定意味着这个二进制文件很糟糕,它可能只是表明发行版供应商在编译二进制文件时做了一些权衡,从而舍弃了部分安全属性。

Checksec 输出的第一行提供了二进制文件的各种安全属性,例如 RELROSTACK CANARYNX 等(我将在后文进行详细解释)。第二行打印出给定二进制文件(本例中为 ls)在这些安全属性的状态(例如,NX enabled 表示为堆栈中的数据没有执行权限)。

示例二进制文件

在本文中,我将使用以下的 “hello world” 程序作为示例二进制文件。

#include <stdio.h>

int main()
{
        printf("Hello World\n");
        return 0;
}
 

请注意,在编译源文件 hello.c 的时候,我没有给 gcc 提供任何额外的标志:

$ gcc hello.c -o hello
 
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

$ ./hello
Hello World

使用 Checksec 运行二进制文件 hello,打印的某些安全属性的状态,与上面的 ls 二进制文件的结果不同(在你的屏幕上,某些属性可能显示为红色):

$ checksec --file=./hello
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   85) Symbols       No    0       0./hello
$

(LCTT 译注:在我的 Ubuntu 22.04 虚拟机,使用 11.3.0 版本的 gcc,结果与上述不太相同,利用默认参数进行编译,会得到 RELRO、PIE、NX 保护是全开的情况。)

更改 Checksec 的输出格式

Checksec 允许自定义各种输出格式,你可以使用 --output 来自定义输出格式。我将选择的输出格式是 JSON 格式,并将输出结果通过管道传输到 jq 实用程序,来得到漂亮的打印。

接下来,确保你已安装好了 jq,因为本教程会使用 jq 从 Checksec 的输出结果中,用 grep 来快速得到某一特定的安全属性状态,并报告该安全属性是否启动(启动为 yes,未启动为 no):

$ checksec --file=./hello --output=json | jq
{
  "hello": {
    "relro": "partial",
    "canary": "no",
    "nx": "yes",
    "pie": "no",
    "rpath": "no",
    "runpath": "no",
    "symbols": "yes",
    "fortify_source": "no",
    "fortified": "0",
    "fortify-able": "0"
  }
}

看一看所有的安全属性

上面的二进制文件 hello 包括几个安全属性。我将该二进制文件与 ls 的二进制文件进行比较,以检查启用的安全属性有何不同,并解释 Checksec 是如何找到此信息。

1、符号(Symbol)

我先从简单的讲起。在编译期间,某些 符号 symbols 包含在二进制文件中,这些符号主要用作于调试。开发软件时,需要用到这些符号,来调试和修复错误。

这些符号通常会从供用户普遍使用的最终二进制文件中删除。删除这些符号不会影响到二进制文件的执行。删除符号通常是为了节省空间,因为一旦符号被删除了,二进制文件就会稍微小一些。在闭源或专有软件中,符号通常都会被删除,因为把这些符号放在二进制文件中,可以很容易地推断出软件的内部工作原理。

根据 Checksec 的结果,在二进制文件 hello 中有符号,但在 ls 的二进制文件中不会有符号。同样地,你还可以用 file 命令,来找到符号的信息,在二进制文件 hello 的输出结果的最后,看到 not stripped,表明二进制文件 hello 有符号:

$ checksec --file=/bin/ls --output=json | jq | grep symbols
    "symbols": "no",

$ checksec --file=./hello --output=json | jq | grep symbols
    "symbols": "yes",

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

Checksec 是如何找到符号的信息呢?Checksec 提供了一个方便的 --debug 选项,来显示运行了哪些函数。因此,运行以下的命令,会显示在 shell 脚本中运行了哪些函数:

$ checksec --debug --file=./hello

在本教程中,我试图寻找 Checksec 查找安全属性信息时,使用了什么底层命令。由于 Checksec 是一个 shell 脚本,因此你始终可以使用 Bash 功能。以下的命令将输出从 shell 脚本中运行的每个命令:

$ bash -x /usr/bin/checksec --file=./hello

如果你滚动浏览上述的输出结果的话,你会看到 echo_message 后面有各个安全属性的类别。以下显示了 Checksec 检测二进制文件是否包含符号时,运行的底层命令:

+ readelf -W --symbols ./hello
+ grep -q '\\.symtab'
+ echo_message '\033[31m96) Symbols\t\033[m  ' Symbols, ' symbols="yes"' '"symbols":"yes",'

上面的输出显示,Checksec 利用 readelf,来读取二进制文件,并提供一个特殊 --symbols 标志,来列出二进制文件中的所有符号。然后它会查找一个特殊值:.symtab,它提供了所能找到的条目的计数(即符号的个数)。你可以在上面编译的测试二进制文件 hello 上,尝试以下命令,得到与 Checksec 查看二进制文件类似的符号信息:

$ readelf -W --symbols ./hello
$ readelf -W --symbols ./hello | grep -i symtab

(LCTT 译注:也可以通过直接查看 /usr/bin/checksec 下的 Checksec 源文件。)

如何删除符号

你可以在编译后或编译时删除符号。

  • 编译后: 在编译后,你可以使用 strip,手动地来删除二进制文件的符号。删除后,使用 file 命令,来检验是否还有符号,现在显示 stripped,表明二进制文件 hello 无符号了:
$ gcc hello.c -o hello
$
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, for GNU/Linux 3.2.0, not stripped
$
$ strip hello
$
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, for GNU/Linux 3.2.0, stripped
$ 
  • 编译时: 你也可以在编译时,用 -s 参数让 gcc 编译器帮你自动地删除符号:
$ gcc -s hello.c -o hello
$
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, for GNU/Linux 3.2.0, stripped
$

重新运行 Checksec,你可以看到现在二进制文件 hellosymbols 这一属性的值是no

$ checksec --file=./hello --output=json | jq | grep symbols
    "symbols": "no",
$

2、Canary(堆栈溢出哨兵)

Canary 是放置在缓冲区和 stack 上的控制数据之间的已知值,它用于监视缓冲区是否溢出。当应用程序执行时,会为其分配两种内存,其中之一就是 。栈是一个具有两个操作的数据结构:第一个操作 push,将数据压入堆栈;第二个操作 pop,以后进先出的顺序从栈中弹出数据。恶意的输入可能会导致栈溢出,或使用特制的输入破坏栈,并导致程序崩溃:

$ checksec --file=/bin/ls --output=json | jq | grep canary
    "canary": "yes",
$
$ checksec --file=./hello --output=json | jq | grep canary
    "canary": "no",
$

Checksec 是如何确定二进制文件是否启用了 Canary 的呢?使用上述同样的方法,得到 Checksec 在检测二进制文件是否启用 Canary 时,运行的底层命令:

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
启用 Canary

为了防止栈溢出等情况,编译器提供了 -stack-protector-all 标志,它向二进制文件添加了额外的代码,来检查缓冲区是否溢出:

$ gcc -fstack-protector-all hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep canary
    "canary": "yes",

Checksec 显示 Canary 属性现已启用。你还可以通过以下方式,来验证这一点:

$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (3)
    83: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2.4
$

3、位置无关可执行文件(PIE)

位置无关可执行文件 Position-Independent Executable (PIE),顾名思义,它指的是放置在内存中某处执行的代码,不管其绝对地址的位置,即代码段、数据段地址随机化(ASLR):

$ checksec --file=/bin/ls --output=json | jq | grep pie
    "pie": "yes",

$ checksec --file=./hello --output=json | jq | grep pie
    "pie": "no",

通常,PIE 仅对 libraries 启用,并不对独立命令行程序启用 PIE。在下面的输出中,hello 显示为 LSB executable,而 libc 标准库(.so) 文件被标记为 LSB shared object

$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, for GNU/Linux 3.2.0, not stripped

$ file /lib64/libc-2.32.so
/lib64/libc-2.32.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262d0c4a4, for GNU/Linux 3.2.0, not stripped

Checksec 查找是否启用 PIE 的底层命令如下:

$ readelf -W -h ./hello | grep EXEC
  Type:                              EXEC (Executable file)

如果你在共享库上尝试相同的命令,你将看到 DYN,而不是 EXEC

$ readelf -W -h /lib64/libc-2.32.so | grep DYN
  Type:                              DYN (Shared object file)
启用 PIE

要在测试程序 hello.c 上启用 PIE,请在编译时,使用以下命令:

$ gcc -pie -fpie hello.c -o hello`

你可以使用 Checksec,来验证 PIE 是否已启用:

$ checksec --file=./hello --output=json | jq | grep pie
    "pie": "yes",
$

现在,应该会显示为 “ PIE 可执行 pie executable ”,其类型从 EXEC 更改为 DYN

$ file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, for GNU/Linux 3.2.0, not stripped

$ readelf -W -h ./hello | grep DYN
  Type:                              DYN (Shared object file)

4、NX(堆栈禁止执行)

NX 代表 不可执行 non-executable 。它通常在 CPU 层面上启用,因此启用 NX 的操作系统可以将某些内存区域标记为不可执行。通常,缓冲区溢出漏洞将恶意代码放在堆栈上,然后尝试执行它。但是,让堆栈这些可写区域变得不可执行,可以防止这种攻击。在使用 gcc 对源程序进行编译时,默认启用此安全属性:

$ checksec --file=/bin/ls --output=json | jq | grep nx
    "nx": "yes",

$ checksec --file=./hello --output=json | jq | grep nx
    "nx": "yes",

Checksec 使用以下底层命令,来确定是否启用了 NX。在尾部的 RW 表示堆栈是可读可写的;因为没有 E,所以堆栈是不可执行的:

$ readelf -W -l ./hello | grep GNU_STACK
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
演示如何禁用 NX

我们不建议禁用 NX,但你可以在编译程序时,使用 -z execstack 参数,来禁用 NX:

$ gcc -z execstack hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep nx
    "nx": "no",

编译后,堆栈会变为可读可写可执行(RWE),允许在堆栈上的恶意代码执行:

$ readelf -W -l ./hello | grep GNU_STACK
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

5、RELRO(GOT 写保护)

RELRO 代表 “ 重定位只读 Relocation Read-Only ”。可执行链接格式(ELF)二进制文件使用全局偏移表(GOT)来动态地解析函数。启用 RELRO 后,会设置二进制文件中的 GOT 表为只读,从而防止重定位攻击:

$ checksec --file=/bin/ls --output=json | jq | grep relro
    "relro": "full",

$ checksec --file=./hello --output=json | jq | grep relro
    "relro": "partial",

Checksec 使用以下底层命令,来查找是否启用 RELRO。在二进制文件 hello 仅启用了 RELRO 属性中的一个属性,因此,在 Checksec 验证时,显示 partial

$ readelf -W -l ./hello | grep GNU_RELRO
  GNU_RELRO      0x002e10 0x0000000000403e10 0x0000000000403e10 0x0001f0 0x0001f0 R   0x1

$ readelf -W -d ./hello | grep BIND_NOW
启用全 RELRO

要启用全 RELRO,请在 gcc 编译时,使用以下命令行参数:

$ gcc -Wl,-z,relro,-z,now hello.c -o hello

$ checksec --file=./hello --output=json | jq | grep relro
    "relro": "full",

现在, RELRO 中的第二个属性也被启用,使程序变成全 RELRO:

$ readelf -W -l ./hello | grep GNU_RELRO
  GNU_RELRO      0x002dd0 0x0000000000403dd0 0x0000000000403dd0 0x000230 0x000230 R   0x1

$ readelf -W -d ./hello | grep BIND_NOW
 0x0000000000000018 (BIND_NOW)       

6、Fortify

Fortify 是另一个安全属性,但它超出了本文的范围。Checksec 是如何在二进制文件中验证 Fortify,以及如何在 gcc 编译时启用 Fortify,作为你需要解决的课后练习。

$ checksec --file=/bin/ls --output=json | jq  | grep -i forti
    "fortify_source": "yes",
    "fortified": "5",
    "fortify-able": "17"

$ checksec --file=./hello --output=json | jq  | grep -i forti
    "fortify_source": "no",
    "fortified": "0",
    "fortify-able": "0"

其他的 Checksec 功能

关于安全性的话题是永无止境的,不可能在本文涵盖所有关于安全性的内容,但我还想提一下 Checksec 命令的一些其他功能,这些功能也很好用。

对多个二进制文件运行 Checksec

你不必对每个二进制文件都进行一次 Checksec。相反,你可以提供多个二进制文件所在的目录路径,Checksec 将一次性为你验证所有文件:

$ checksec --dir=/usr

对进程运行 Checksec

Checksec 除了能检查二进制文件的安全属性,Checksec 还能对程序起作用。以下的命令用于查找你系统上所有正在运行的程序的安全属性。如果你希望 Checksec 检查所有正在运行的进程,可以使用 --proc-all,或者你也可以使用进程名称,选择特定的进程进行检查:

$ checksec --proc-all

$ checksec --proc=bash

对内核运行 Checksec

除了本文介绍的用 Checksec 检查用户态应用程序的安全属性之外,你还可以使用它来检查系统内置的 内核属性 kernel properties

$ checksec --kernel

快来试一试 Checksec 吧

Checksec 是一个能了解哪些用户空间和内核的安全属性被启用的好方法。现在,你就可以开始使用 Checksec,来了解每个安全属性是什么,并明白启用每个安全属性的原因,以及它能阻止的攻击类型。


via: https://opensource.com/article/21/6/linux-checksec

作者:Gaurav Kamathe 选题:lujun9972 译者:chai001125 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过安全的网络连接在远程计算机上调用命令或程序。

有一天,我正在测试如何在 将文件或目录复制到多个位置和系统时保持完整的文件权限。当我想检查远程系统上的文件权限时,我必须通过 SSH 登录它并检查属性。从远程系统多次登录和注销的过程让我有点烦,我想,如果我可以在远程 Linux 系统上通过 SSH 执行命令就好了。

幸运的是,在浏览了 ssh 命令的手册页后,我找到了一个解决办法。

如果你想知道如何本地运行远程系统上运行命令或脚本,而不登录到远程系统,下面的内容会告诉你如何做。

1、通过 SSH 在远程 Linux 系统上执行命令

从本地系统通过 SSH 在远程系统上运行命令或脚本的典型方法是:

$ ssh <username@IP_Address-or-Doman_name> <Command-or-Script>

允许我给你们举几个例子:

1.1、通过 SSH 在远程系统上运行单个命令

假设你想要 查找远程 Linux 系统的内核详细信息。为此,只需运行:

$ ssh [email protected] uname -a

这里,

  • sk 是远程系统的用户名,
  • 192.168.225.22 是远程系统的 IP 地址,
  • uname -a 是我想在远程系统上运行的命令。

示例输出:

通过 SSH 在远程 Linux 系统上执行命令

看到没?我并没有实际登录到远程系统,但通过 SSH 在远程系统上执行了 uname 命令,并在本地系统的终端上显示了输出。

你还可以像下面这样用引号指定命令。

$ ssh [email protected] "uname -a"

或者,

$ ssh [email protected] 'uname -a'

如果你已经 更改了 SSH 协议的默认端口,只需使用 -p 参数指定它。

$ ssh -p 2200 [email protected] uname -a

1.2、通过 SSH 在远程主机上执行多个命令

你还可以在远程主机上运行多个命令,方法是将它们放在引号中。

$ ssh [email protected] "uname -r && lsb_release -a"

或者:

$ ssh [email protected] "uname -r ; lsb_release -a"

上面的命令将显示我的 Ubuntu 服务器的内核版本和发行版详细信息。

示例输出:

在 Linux 上通过 SSH 在远程主机上运行多个命令

正如一位读者在下面的评论部分提到的那样,你应该用引号指定多个命令。如果不使用引号,第一个命令将在远程系统上执行,第二个命令将仅在本地计算机上执行。整个带引号的命令将按预期在远程计算机上运行。

提示: 了解 &&; 在命令中的区别:

&& 操作符只有在第一个命令成功时才执行第二个命令。

示例:

sudo apt-get update && sudo apt-get upgrade

在上述示例中,如果第一个命令成功,才会执行 sudo apt-get upgrade。否则,它将不会运行。

; 操作符会执行第二个命令,无论第一个命令是成功还是失败。

示例:

sudo apt-get update ; sudo apt-get upgrade

在上述示例中,即使第一个命令失败,sudo apt-get upgrade 也会执行。

1.3、通过 SSH 在远程机器上调用有 sudo 权限的命令

有些命令需要 sudo 权限才能运行。例如,以下命令将在我的远程系统上安装 apache2

$ ssh -t [email protected] sudo apt install apache2

示例输出:

通过 SSH 在远程机器上运行有 Sudo 权限的命令

注意到了吗?我在上面的命令中使用了 -t 标志,我们需要使用它来强制进行伪终端分配。它用于在远程机器上执行任意基于屏幕的程序,这非常有用。例如,在实现菜单服务时。

另外,我输入了两次密码。第一次是远程用户的密码,以便从本地系统通过 SSH 访问远程系统,第二次是为了向远程用户赋予 sudo 权限,以便安装应用程序(在本例中为 apache2)。

让我们用以下命令检查 Apache 服务是否正在运行:

$ ssh -t [email protected] sudo systemctl status apache2
[email protected]'s password: 
[sudo] password for sk: 
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
Active: active (running) since Thu 2019-12-19 11:08:03 UTC; 52s ago
Main PID: 5251 (apache2)
Tasks: 55 (limit: 2318)
CGroup: /system.slice/apache2.service
├─5251 /usr/sbin/apache2 -k start
├─5253 /usr/sbin/apache2 -k start
└─5254 /usr/sbin/apache2 -k start

Dec 19 11:08:03 ubuntuserver systemd[1]: Starting The Apache HTTP Server...
Dec 19 11:08:03 ubuntuserver apachectl[5227]: AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 2409:4072:51f:a1b6:a00:27ff:f
Dec 19 11:08:03 ubuntuserver systemd[1]: Started The Apache HTTP Server.

同样的,我们可以通过 SSH 在本地系统上运行远程系统上的任何命令或脚本。

1.4、通过 SSH 在远程系统上运行本地脚本

让我们在本地系统上创建一个简单的脚本来显示关于远程系统的发行版名称、包管理和基本细节等。

$ vi system_information.sh

添加以下行:

#!/bin/bash
#Name: Display System Details
#Owner: OSTechNIx
#----------------------------
echo /etc/*_ver* /etc/*-rel*; cat /etc/*_ver* /etc/*-rel*

按下 ESC 键,输入 :wq 保存退出。

现在,通过 SSH 命令在远程系统上运行这个脚本:

$ ssh [email protected] 'bash -s' < system_information.sh

示例输出:

[email protected]'s password: 
/etc/debian_version /etc/lsb-release /etc/os-release
buster/sid
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

如果你没有在上面的命令中指定 bash -s,你将获得远程系统的详细信息,但伪终端不会被分配。

1.5、将远程主机的命令输出保存到本地主机

如果你希望与支持团队或同事共享远程系统上运行的命令输出,那么这非常有用。

以下命令将通过 SSH 在远程系统运行 du -ah,并将输出保存在本地系统的 diskusage.txt 文件中。

$ ssh [email protected] du -ah > diskusage.txt

然后,你可以通过使用 cat 命令或文本编辑器查看 diskusage.txt 文件来分析磁盘使用细节。

$ cat diskusage.txt 
4.0K ./.profile
4.0K ./.gnupg/private-keys-v1.d
8.0K ./.gnupg
76K ./data/image.jpg
128K ./data/file.pdf
20K ./data/text.docx
5.9M ./data/audio.mp3
6.1M ./data
0 ./.sudo_as_admin_successful
4.0K ./pacman?inline=false
4.0K ./.bash_logout
4.0K ./.wget-hsts
4.0K ./.bash_history
0 ./.cache/motd.legal-displayed
4.0K ./.cache
4.0K ./deb-pacman_1.0-0.deb
4.0K ./.bashrc
6.2M .

1.6、配置 SSH 密钥认证,避免输入密码

如果你经常在远程系统上运行命令,你可能需要配置基于 SSH 密钥的身份验证,以便每次跳过密码输入。更多细节可以在以下链接中找到。

Linux 系统下如何配置 SSH 密钥认证

配置了基于 SSH 密钥的认证后,我们可以通过 SSH 在远程机器上执行命令,从而不需要输入密码:

$ ssh [email protected] sudo apt update

2、通过 sshpass 在远程机器上运行命令

如果你不想配置基于 SSH 密钥的身份验证,你可以使用 sshpass 实用程序。

2.1、什么是 sshpass?

sshpass 是为使用键盘交互密码身份验证模式运行 ssh 而设计的,但它以非交互的方式。简单来说,sshpass 提供了非交互式的方式来验证 SSH 会话。

SSH 使用直接 TTY 访问来确保密码确实是由交互式键盘用户发出的。sshpass 在一个专用 tty 中运行 SSH,让它误以为从交互用户那里获得了密码。

2.2、在 Linux 中安装 sshpass

在许多 Linux 发行版的默认仓库中都有 sshpass 实用程序。例如,在 Debian、Ubuntu 及其衍生版本中,你可以使用下面的命令来安装 sshpass

$ sudo apt install sshpass

2.3、通过 SSH 和 sshpass 在远程机器上执行命令

sshpass 可以通过参数接受密码,或者通过环境变量读取密码,也可以从文本文件中读取密码。

警告: 所有这些方法都是 高度不安全的。所有系统用户都可以通过 ps 命令看到命令中的密码。不建议在生产中使用这些方法。最好使用基于密钥的身份验证。

让我们看看每种方法的示例。

将密码作为参数提供

将密码作为参数提供,使用 -p 选项,如下所示:

$ sshpass -p <remote-password> ssh remoteuser@ip-address <command-to-execute>

示例输出:

$ sshpass -p ubuntu ssh [email protected] uname -a

其中,

  • -p ubuntu - 提供远程系统的密码。
  • [email protected] - 远程系统用户名和地址。
  • uname -a - 要在远程计算机上执行的命令。

示例输出:

Linux Ubuntu22CT 5.15.60-1-pve #1 SMP PVE 5.15.60-1 (Mon, 19 Sep 2022 17:53:17 +0200) x86_64 x86_64 x86_64 GNU/Linux
密码作为环境变量提供

在这个方法中,我们声明一个名为 SSHPASS 的环境变量,用远程环境的密码作为其值。然后我们使用 -e 标志,如下所示:

$ SSHPASS=ubuntu sshpass -e ssh [email protected] uname -a
从文本文件中读取密码

使用 echo 命令在文本文件中追加密码:

$ echo "ubuntu" > mypassword.txt

现在,将密码文件传递给带有 -f 标志的 sshpass,如下所示:

$ sshpass -f mypassword.txt ssh [email protected] uname -a

通过 SSH 和 sshpass 在远程机器上执行命令

总结

在本教程中,我们学习了一些通过安全的网络连接在远程计算机上调用命令或程序的方法。在所有的方法中,sshpass 方法是最不安全的,建议用户避免在生产系统中使用它。


via: https://ostechnix.com/execute-commands-on-remote-linux-systems-via-ssh/

作者:sk 选题:lkxed 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出