MySQL 데이터 변경 감지 (trigger) + 시스템 명령어 사용 (udf)

리눅스/MySQL|2020. 5. 31. 07:35
반응형

아래는 트리거 예제입니다.

테스트 테이블을 생성합니다.

test 테이블에는 데이터를 넣어 놓고,

test2 테이블에는 구조만 같게 해 놓고 데이터는 넣지 않습니다.

그리고 트리거 설정 후 부터는 test 에 insert 되는 데이터를 test2 에도 insert 되게 합니다.



[테스트 준비]

mysql> use test;


mysql> create table test (no int(3) AUTO_INCREMENT PRIMARY KEY, name varchar(20), age int(3));

mysql> insert test (name, age) values ('CDH', '20');

mysql> insert test (name, age) values ('JJE', '21');


mysql> create table test2 (no int(3) AUTO_INCREMENT PRIMARY KEY, name varchar(20), age int(3));



[트리거 생성]

mysql> delimiter $$

create trigger test_trigger

after insert on test for each row

begin

  insert into test2 values(new.no, new.name, new.age);

end

$$

delimiter ;



[설명]

* test_trigger : 트리거 이름

* after insert : insert 되고 나서 실행 (데이터 처리 전에 실행하려면 before 를 사용)

* on test : test 테이블 연결

* for each row : 각 행마다 실행

* begin ~ end : 조건에 맞으면 begin 과 end 사이 구문 실행 (insert, update, delete 감지 가능)

* new : insert 사용시 new, delete 사용시 old, update 사용시 old, new 를 사용할 수 있습니다.

* delimiter 뒤에 오는 문자로 쿼리 마치는 문자를 정의하는 것입니다.

   내용중에 세미콜론(;) 이 들어갈 수 있으니 $$ 로 변경 해놓고, 모든 작업이 완료 후 다시 ; 로 원복 하였습니다.


[참고]

* 트리거 보기

show triggers;


* 트리거 삭제

drop trigger 트리거명;



[테스트]

데이터를 추가로 입력하여 두 개의 테이블에 들어갔는지 확인합니다.


mysql> insert test (name, age) values ('CJW', '3');

mysql> insert test (name, age) values ('CHY', '5');


mysql> select * from test;

mysql> select * from test2;



[원격지 DB 테이블 연결]

mysql> 쉘 상에서는 직접적인 연결을 지원하지 않고,

내부에 원격지 테이블 연결이 가능하므로 연결을 통하여 insert 를 하면 될 것 같습니다.

(참조 : https://icoon22.tistory.com/251)

(단점 : show table testtbl 시 패스워드 노출)


CREATE TABLE testtbl (

 id INT AUTO_INCREMENT PRIMARY KEY,

 col1 VARCHAR(100) DEFAULT NULL,

 col2 VARCHAR(200) DEFAULT NULL

) ENGINE=FEDERATED 

  DEFAULT CHARSET=UTF8

  CONNECTION='mysql://userid:userpw@192.168.10.2:3306/testdb/testtbl;



[MySQL 에서 시스템 명령어 사용]

MySQL 에서 OS 명령어를 실행하려면 UDF 라이브러리가 필요합니다.


1) 리눅스

centos : https://ymj0078.tistory.com/5

ubuntu : https://oranke.tistory.com/273


(아래는 Ubuntu 18.04 에서 진행하였습니다)


# git clone https://github.com/mysqludf/lib_mysqludf_sys.git

# cd lib_mysqludf_sys/


# vi Makefile

LIBDIR=/usr/lib/mysql/plugin


install:

        gcc -Wall -I/usr/include/mysql -I. -fPIC lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so 

* OS 에 따라 /usr/lib/mysql/plugin 또는 /usr/lib64/mysql/plugin 사용

* /usr/include/mysql 디렉토리가 없는 경우

  Ubuntu : apt -y install libmysqld-dev

  CentOS : yum -y install mysql-devel 패키지 추가 설치


# gcc -shared -o lib_mysqludf_sys.so lib_mysqludf_sys.c -I/usr/include/mysql

# cp -arp lib_mysqludf_sys.so /usr/lib/mysql/plugin/


플러그인 추가 (mysql 로그인 후)

DROP FUNCTION IF EXISTS lib_mysqludf_sys_info;

DROP FUNCTION IF EXISTS sys_get;

DROP FUNCTION IF EXISTS sys_set;

DROP FUNCTION IF EXISTS sys_exec;

DROP FUNCTION IF EXISTS sys_eval;


CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';

CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';

CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';

CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';

CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';


확인

select * from mysql.func;


테스트
select sys_exec('touch /tmp/test_mysql');

동작이 되지 않을 경우 쉘에서 아래와 같이 입력합니다.
(참조 : https://oranke.tistory.com/273)

# apparmor_status
결과에 /usr/sbin/mysqld 를 차단하지 않았나 확인해 볼 것
등록되어있는 경우 삭제를 해야 합니다.

# ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
# apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld

재확인
sudo apparmor_status

apparmor 와 mysql 재구동
# systemctl restart mysql
# systemctl restart apparmor

그리고 다시 테스트
select sys_exec('touch /tmp/test_mysql');

그렇다면 MySQL trigger 와 udf 를 합친 방법을 사용해 봅시다.

맨 위의 예제에서 begin 과 end 사이에 아래 내용을 넣으면..

begin
    SET @exec_var = sys_exec(CONCAT('touch /tmp/', new.name));
end

exec_var 라는 mysql 변수에 sys_exec 결과를 넣는다는 뜻이지만 실제로 실행이 되어집니다.
CONCAT() 에 있는 'touch /tmp/' 와 콤마(,) 뒤의 new.name (새로운 name 필드값) 은 아래와 같이 이어붙인 명령이 됩니다.

insert into test (name, age) values ('cdh', '22'); 라고 입력시
=> touch /tmp/cdh 라고 시스템 명령을 수행한 것과 같습니다.

한 번 더 해보면.. (CONCAT 내의 띄어쓰기 잘 살펴볼 것)

begin
  SET @exec_var = sys_exec(CONCAT('touch /tmp/', new.name, ' /tmp/', new.age));
end

insert into test (name, age) values ('cdh', '22'); 라고 입력시
=> touch /tmp/cdh /tmp/22 라고 시스템 명령을 수행한 것과 같습니다.
    그래서 /tmp 디렉토리 내에 cdh 와 22 라는 파일이 생성된 것을 볼 수 있습니다.


2) 윈도우


아래 URL 은 64bit 용 dll 파일 입니다.

https://github.com/sqlmapproject/sqlmap/files/1789515/lib_mysqludf_sys_64.zip


lib_mysqludf_sys_64.zip

{mysql 설치디렉토리}\lib\plugin 안에 저장합니다.


디렉토리가 보이지 않을 경우 아래와 같이 플러그인 경로를 확인하고 실제로 존재하지 않을 경우

디렉토리를 수동으로 생성해줍니다.


mysql> select @@plugin_dir;


라이브러리 추가


mysql> use mysql;

mysql> create function sys_exec returns int soname 'lib_mysqludf_sys.so';


확인


mysql> selet * from mysql.func;


시스템 명령어 사용 예 (리눅스와 동일. 단 경로는 슬래시 두개로 사용)


1) 그냥 사용시

mysql> select sys_exec("echo aaa > c://test.txt");


반응형

댓글()