강좌/RaspberryPI 활용

라즈베리파이 Telegram - PHP를 이용하여 메시지 보내기

acidpop 2015. 8. 13. 16:21
반응형

앞에서 Telegram BOT 강좌를 이용하여 텔레그램이 설치가 되었다면

 

라즈베리파이 내부에서만 텔레그램을 통해 메시지를 보낼수 있을것이다.

 

 

Telegram BOT 강좌 4부 참조

 

2015/07/21 - [강좌/RaspberryPI 활용] - 라즈베리파이 Telegram BOT 만들기 4부 - Telegram CLI 데몬 실행 및 서비스 등록

 

ex)

echo "msg 홍길동 메시지 보내봅니다" | nc localhost 8888

 

nc 뒤에 localhost 만 라즈베리파이의 IP로 변경하면 다른 장비에서도 사용 할 수 있지 않을까? 싶지만 작동하지 않는다.

 

echo "msg 홍길동 메시지 보내봅니다" | nc 192.168.0.199 8888

 

분명 -P 옵션으로 8888 포트를 열었지만 라즈베리파이 내부에서만 작동 하지 다른 장비에서는 작동하지 않는다.

 

그 비밀(?)은 바로 Telegram CLI 의 소스에 숨겨져 있다.

 

Telegram 소스가 위치한 경로로 이동해보자.

 

cd /home/pi/tg

 

여기에서 main.c 파일을 vi 또는 nano 에디터로 열어 보면

 

int main 함수 아래쪽 (필자는 919 라인에 있다)을 보자.

 

 

 882   int main (int argc, char **argv) {
 883   signal (SIGSEGV, termination_signal_handler);
 884   signal (SIGABRT, termination_signal_handler);
 885   signal (SIGBUS, termination_signal_handler);
 886   signal (SIGQUIT, termination_signal_handler);
 887   signal (SIGFPE, termination_signal_handler);
 888
 889   signal (SIGPIPE, SIG_IGN);
 890
 891   signal (SIGTERM, sig_term_handler);
 892   signal (SIGINT, sig_term_handler);
 893
 894   rl_catch_signals = 0;
 895
 896
 897   log_level = 10;
 898
 899   args_parse (argc, argv);
 900
 901   change_user_group ();
 902
 903   if (port > 0) {
 904     struct sockaddr_in serv_addr;
 905     int yes = 1;
 906     sfd = socket (AF_INET, SOCK_STREAM, 0);
 907     if (sfd < 0) {
 908       perror ("socket");
 909       exit(1);
 910     }
 911
 912     if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
 913       perror("setsockopt");
 914       exit(1);
 915     }
 916     memset (&serv_addr, 0, sizeof (serv_addr));
 917
 918     serv_addr.sin_family = AF_INET;
 919     serv_addr.sin_addr.s_addr = accept_any_tcp ? INADDR_ANY : htonl (0x7f000001);
 920     serv_addr.sin_port = htons (port);

 

 

919 라인에서 설정하는 저 부분 중 accept_any_tcp 플래그가 True 일때는 INADDR_ANY 를

FALSE 라면 htonl(0x7f000001) 값을 세팅하게 되어 있다.

 

htonl(0x7f000001) 이 값은 INADDR_LOOPBACK 이라는 플래그로 정의되어 있는데

 

LOOPBACK 네트워크의 접속만 허용하겠다 라는 의미이다.

 

몇일전 Telegram cli 소스에서는 accept_any_tcp 라는 항목이 없었는데 최근 소스에 추가가 되어 있다.

 

 

4부에서 데몬으로 실행할때 옵션에서 accept_any_tcp 라는 옵션만 더 추가하면 다른 네트워크에서도 접근이 가능한 소켓을 Listen 한다.

 

 

telegram-cli -h 를 해도 나오지 않는 항목이기 때문에 소스를 보지 않는 이상 알 수 없는 옵션이다.

 

(최근 소스를 받아보면 help 에 해당 옵션이 나온다)

 

 

 

bin/telegram-cli -s bot/basicbot.lua -P 8888 -e "contact_list" --accept_any_tcp -L /var/log/telegram.log -d & 

 

위 명령으로 데몬을 띄우면 다른 장비에서도 라즈베리파이의 IP와 8888 포트 정보를 이용하여

 

netcat 을 통해 메시지를 보낼 수 있다.

 

 

 


 

 

제목과 전혀 다른 내용이 전개 되었는데 PHP는 도대체 어디 간거야? 라는 의문이 있을것이다.

 

지금까지의 내용은 그냥 알아두기 수준으로만 하고 넘어가는것이 좋다.

 

왜냐하면 위와 같이 LOOPBACK 네트워크가 아닌 모든 네트워크에서 접속을 다 받을수 있다면 공격자가 라즈베리파이의 IP와 포트로 수많은 메시지를 보낼 수가 있게된다.

 

Telegram CLI 의 소켓은 보안성이 없고 그저 모든 명령을 다 받아 처리하게 되어 있기 때문에

 

심각한 보안 문제가 발생 할 수 있다.

 

telegram-cli 로 모르는 사람에게 온갖 스팸 메시지가 보내 질 수도 있는것이다.

 

 

 

필자는 LOOPBACK 으로만 소켓을 열고 php 를 이용해서 메시지를 전송한다.

 

 

준비 과정은 다음과 같다.

 

1. 라즈베리파이에 Apache+ php 또는 NginX + php 를 설치 한다.

 

웹서버와 php 를 설치하는 방법은 수많은 블로그에서 다루고 있으니 생략한다.

 

필자는 Apache + PHP 로 구성하였다.

 

2. php 파일을 작성한다.

 

PHP를 이용해서 텔레그램으로 메시지를 보내는 방법으로 다음과 같이 코딩하였다.

 

  1. PHP에서 GET parameter 중 password 키를 지정하여 해당 Password 값과 일치 하지 않는다면 요청을 무시한다.

  2. password 가 일치 한다면 Text File 을 전송 받는다.

  3. 전송 받은 Text File을 Local Network 의 Telegram-CLI 에 전송 하도록 요청한다.

 

필자는 PHP 개발을 잘 몰라서 여기저기 구글링하여 다음과 같이 개발하였다.

<?php
header("Content-Type: text/html; charset=UTF-8");
// 4.1.0 이전의 PHP에서는, $_FILES 대신에 $HTTP_POST_FILES를
// 사용해야 합니다.



$pw=$_POST["password"];

// 뒷부분의 엄청나게 긴 패스워드는 'password' 라는 문자열을 SHA256 으로 해쉬한 결과값이다.
// 각 사용자는 자신의 고유 Password 를 설정하여 사용하면 된다.
$pwcmp = strcmp($pw, '5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8');

$tgsend_text_shell="/home/pi/tg/bot/shell/tgtext.sh";
$ipauth="/tmp/ipauth.txt";

// Password 가 일치하지 않는 경우 접속한 사용자의 IP를 텔레그램으로 전송
if($pwcmp){
    echo "Unauthorized user";
    ignore_user_abort(1); 
    $f = fopen($ipauth, "w"); 
    $tp="(".date('Y/m/d-H:i:s').") ".$_SERVER['REMOTE_ADDR']; 
    fwrite($f, "인증되지 않은 사용자가 File Upload를 시도하였습니다\n");
    fwrite($f, $tp."\n");
    $pwtxt   ="PASSWORD : ".$pw;
    fwrite($f, $pwtxt."\n");
    fwrite($f, $_SERVER['HTTP_USER_AGENT']."\n");
    fclose($f);  
    exec($tgsend_text_shell." ".escapeshellarg($ipauth));
}else{

    $uploaddir = '/tmp/';
    $uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

    if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo "파일이 유효하고, 성공적으로 업로드 되었습니다.\n";
    } else {
        print "파일이 유효하지 않습니다!\n";
    }

    // 업로드 된 Text 파일을 Telegram 으로 전송한다.
    exec($tgsend_text_shell." "."홍길동"." ".escapeshellarg($uploadfile));
}

?>

위 코드를 아래의 경로에 저장한다.

 

/var/www/tgcli.php

 

 

 

주의 :

위 코드에서 "5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8" 

 

이 Password 부분은 각 사용자가 변경하여 사용하여야 한다.

 

필자는 SHA256 생성기 (http://www.convertstring.com/ko/Hash/SHA256) 를 이용해서 암호를 해쉬한 값을 사용한다.

 

위 Hash 코드는 'password' 라는 문자열을 SHA256으로 해쉬한 값이다. 그대로 사용하면 안된다.

 

 

좀 더 보안에 신경을 써야 한다면 php 파일 내부에 암호를 저장하는게 아닌 다른곳에 저장해두고 php에서 읽어오게 해야 더 좋을듯..

 

 

 

위와 같이 저장하였다면 90%는 성공이다.

 

이제 다른 장비에서 사용 하는 방법은 다음과 같다.

 

필자는 curl 이라는 유틸을 이용해서 사용한다.

 

다른 리눅스 장비에서 다음 명령어를 입력하여 실행해보자.

 

 

curl --form userfile=@/tmp/temp.txt --form password=5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8 http://192.168.0.199/tgcli.php

 

 

 

 

/tmp/temp.txt 파일을 라즈베리파이의 php 로 전송을 하는 명령어이다.

 

당연히 /tmp/temp.txt 파일이 있어야 한다.

 

모든 과정이 정상적으로 되었다면 텔레그램으로 해당 텍스트 파일의 내용이 전송 되었을 것이다.

 

 

 

위 php 파일을 응용하면 파일이 아닌 GET Parameter에 내용을 직접 전달 할 수도 있다.

 

 


 

 

이 강좌는 난이도가 조금 있습니다.

 

차근 차근 따라해 보시고 잘 안되는 부분이나 궁금하신 점은 질문 게시판을 이용해 주세요.

 

감사합니다.