1 /*
2 * ModSecurity, http://www.modsecurity.org/
3 * Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4 *
5 * You may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * If any of the files related to licensing are missing or if you have any
11 * other questions related to licensing please contact Trustwave Holdings, Inc.
12 * directly using the email address security@modsecurity.org.
13 *
14 */
15
16 #include "src/operators/verify_cc.h"
17
18 #include <pcre.h>
19 #include <iostream>
20 #include <cstring>
21 #include <vector>
22
23 #include "src/operators/operator.h"
24
25 #if PCRE_HAVE_JIT
26 #define pcre_study_opt PCRE_STUDY_JIT_COMPILE
27 #else
28 #define pcre_study_opt 0
29 #endif
30
31
32 namespace modsecurity {
33 namespace operators {
34
~VerifyCC()35 VerifyCC::~VerifyCC() {
36 if (m_pc != NULL) {
37 pcre_free(m_pc);
38 m_pc = NULL;
39 }
40 if (m_pce != NULL) {
41 #if PCRE_HAVE_JIT
42 pcre_free_study(m_pce);
43 #else
44 pcre_free(m_pce);
45 #endif
46 m_pce = NULL;
47 }
48 }
49
50 /**
51 * Luhn Mod-10 Method (ISO 2894/ANSI 4.13)
52 */
luhnVerify(const char * ccnumber,int len)53 int VerifyCC::luhnVerify(const char *ccnumber, int len) {
54 int sum[2] = { 0, 0 };
55 int odd = 0;
56 int digits = 0;
57 int i;
58
59 /* Weighted lookup table which is just a precalculated (i = index):
60 * i*2 + (( (i*2) > 9 ) ? -9 : 0)
61 */
62 /* weight lookup table */
63 static const int wtable[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};
64
65
66 /* Add up only digits (weighted digits via lookup table)
67 * for both odd and even CC numbers to avoid 2 passes.
68 */
69 for (i = 0; i < len; i++) {
70 if (ccnumber[i] >= (0 + 48) && ccnumber[i] <= (9 + 48)) {
71 sum[0] += (!odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0'));
72 sum[1] += (odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0'));
73 odd = 1 - odd; /* alternate weights */
74 digits++;
75 }
76 }
77
78 /* No digits extracted */
79 if (digits == 0) {
80 return 0;
81 }
82
83 /* Do a mod 10 on the sum */
84 sum[odd] %= 10;
85
86 /* If the result is a zero the card is valid. */
87 return sum[odd] ? 0 : 1;
88 }
89
90
91
init(const std::string & param2,std::string * error)92 bool VerifyCC::init(const std::string ¶m2, std::string *error) {
93 const char *errptr = NULL;
94 int erroffset = 0;
95
96 m_pc = pcre_compile(m_param.c_str(), PCRE_DOTALL|PCRE_MULTILINE,
97 &errptr, &erroffset, NULL);
98 if (m_pc == NULL) {
99 error->assign(errptr);
100 return false;
101 }
102
103 m_pce = pcre_study(m_pc, pcre_study_opt, &errptr);
104 if (m_pce == NULL) {
105 if (errptr == NULL) {
106 /*
107 * Per pcre_study(3) m_pce == NULL && errptr == NULL means
108 * that no addional information is found, so no need to study
109 */
110 return true;
111 }
112 error->assign(errptr);
113 return false;
114 }
115
116 return true;
117 }
118
119
evaluate(Transaction * t,RuleWithActions * rule,const std::string & i,std::shared_ptr<RuleMessage> ruleMessage)120 bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
121 const std::string& i, std::shared_ptr<RuleMessage> ruleMessage) {
122 int offset = 0;
123 int target_length = i.length();
124
125 for (offset = 0; offset < target_length; offset++) {
126 std::string match;
127 int ovector[33];
128 memset(ovector, 0, sizeof(ovector));
129 int ret = pcre_exec(m_pc, m_pce, i.c_str(), i.size(), offset,
130 0, ovector, 33) > 0;
131
132 /* If there was no match, then we are done. */
133 if (ret == PCRE_ERROR_NOMATCH) {
134 break;
135 }
136 if (ret < 0) {
137 return false;
138 }
139 if (ret > 0) {
140 match = std::string(i, ovector[0], ovector[1] - ovector[0]);
141 int is_cc = luhnVerify(match.c_str(), match.size());
142 if (is_cc) {
143 if (t) {
144 if (rule && rule->hasCaptureAction()) {
145 t->m_collections.m_tx_collection->storeOrUpdateFirst(
146 "0", std::string(match));
147 ms_dbg_a(t, 7, "Added VerifyCC match TX.0: " + \
148 std::string(match));
149 }
150 ms_dbg_a(t, 9, "CC# match \"" + m_param +
151 "\" at " + i + ". [offset " +
152 std::to_string(offset) + "]");
153 }
154 return true;
155 }
156 }
157 }
158
159 return false;
160 }
161
162
163 } // namespace operators
164 } // namespace modsecurity
165
166